diff --git a/Client/pom.xml b/Client/pom.xml index e2f3f7e5f2..7b2d1eeedf 100644 --- a/Client/pom.xml +++ b/Client/pom.xml @@ -9,7 +9,7 @@ org.xdi oxauth - 1.3.2.Final + 1.4.1.Final diff --git a/Client/src/test/java/org/xdi/oxauth/BaseTest.java b/Client/src/test/java/org/xdi/oxauth/BaseTest.java index eac269e2bd..62a61021b5 100644 --- a/Client/src/test/java/org/xdi/oxauth/BaseTest.java +++ b/Client/src/test/java/org/xdi/oxauth/BaseTest.java @@ -13,12 +13,8 @@ import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.chrome.ChromeDriver; -import org.openqa.selenium.firefox.FirefoxDriver; import org.openqa.selenium.htmlunit.HtmlUnitDriver; -import org.openqa.selenium.remote.DesiredCapabilities; -import org.openqa.selenium.remote.RemoteWebDriver; import org.openqa.selenium.support.ui.ExpectedCondition; -import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; import org.testng.ITestContext; import org.testng.annotations.BeforeTest; @@ -28,12 +24,9 @@ import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; -import java.net.MalformedURLException; -import java.net.URL; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.TimeUnit; import static org.testng.Assert.*; @@ -317,7 +310,7 @@ public void discovery(ITestContext context) throws Exception { assertTrue(response.getScopeToClaimsMapping().size() > 0, "The scope to claims mapping is empty"); assertTrue(response.getResponseTypesSupported().size() > 0, "The responseTypesSupported is empty"); assertTrue(response.getGrantTypesSupported().size() > 0, "The grantTypesSupported is empty"); - assertTrue(response.getAcrValuesSupported().size() > 0, "The acrValuesSupported is empty"); + assertTrue(response.getAcrValuesSupported().size() == 0, "The acrValuesSupported is not empty"); assertTrue(response.getAmrValuesSupported().size() > 0, "The amrValuesSupported is empty"); assertTrue(response.getSubjectTypesSupported().size() > 0, "The subjectTypesSupported is empty"); assertTrue(response.getIdTokenSigningAlgValuesSupported().size() > 0, "The idTokenSigningAlgValuesSupported is empty"); diff --git a/Client/src/test/java/org/xdi/oxauth/interop/SupportClaimsRequestSpecifyingSubValue.java b/Client/src/test/java/org/xdi/oxauth/interop/SupportClaimsRequestSpecifyingSubValue.java new file mode 100644 index 0000000000..f8ccf8c217 --- /dev/null +++ b/Client/src/test/java/org/xdi/oxauth/interop/SupportClaimsRequestSpecifyingSubValue.java @@ -0,0 +1,227 @@ +package org.xdi.oxauth.interop; + +import org.apache.http.client.CookieStore; +import org.apache.http.impl.client.BasicCookieStore; +import org.apache.http.impl.client.DefaultHttpClient; +import org.jboss.resteasy.client.ClientExecutor; +import org.jboss.resteasy.client.core.executors.ApacheHttpClient4Executor; +import org.testng.annotations.Parameters; +import org.testng.annotations.Test; +import org.xdi.oxauth.BaseTest; +import org.xdi.oxauth.client.*; +import org.xdi.oxauth.client.model.authorize.Claim; +import org.xdi.oxauth.client.model.authorize.ClaimValue; +import org.xdi.oxauth.client.model.authorize.JwtAuthorizationRequest; +import org.xdi.oxauth.dev.HostnameVerifierType; +import org.xdi.oxauth.model.authorize.AuthorizeErrorResponseType; +import org.xdi.oxauth.model.common.Prompt; +import org.xdi.oxauth.model.common.ResponseType; +import org.xdi.oxauth.model.crypto.signature.RSAPublicKey; +import org.xdi.oxauth.model.crypto.signature.SignatureAlgorithm; +import org.xdi.oxauth.model.jws.RSASigner; +import org.xdi.oxauth.model.jwt.Jwt; +import org.xdi.oxauth.model.jwt.JwtClaimName; +import org.xdi.oxauth.model.jwt.JwtHeaderName; +import org.xdi.oxauth.model.register.ApplicationType; +import org.xdi.oxauth.model.util.StringUtils; + +import java.util.Arrays; +import java.util.List; +import java.util.UUID; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +/** + * OC5:FeatureTest-Support claims Request Specifying sub Value + * If that user is logged in, the request succeeds, otherwise it fails. + * + * @author Javier Rojas Blum + * @version 1.0, 07/21/2014 + */ +public class SupportClaimsRequestSpecifyingSubValue extends BaseTest { + + @Parameters({"userId", "userSecret", "redirectUri", "redirectUris", "hostnameVerifier"}) + @Test + public void supportClaimsRequestSpecifyingSubValueSucceed( + final String userId, final String userSecret, final String redirectUri, final String redirectUris, + String hostnameVerifier) throws Exception { + showTitle("OC5:FeatureTest-Support claims Request Specifying sub Value (succeed)"); + + List responseTypes = Arrays.asList(ResponseType.TOKEN, ResponseType.ID_TOKEN); + + // 1. Register client + RegisterRequest registerRequest = new RegisterRequest(ApplicationType.WEB, "oxAuth test app", + StringUtils.spaceSeparatedToList(redirectUris)); + registerRequest.setResponseTypes(responseTypes); + + RegisterClient registerClient = new RegisterClient(registrationEndpoint); + registerClient.setRequest(registerRequest); + RegisterResponse registerResponse = registerClient.exec(); + + showClient(registerClient); + assertEquals(registerResponse.getStatus(), 200, "Unexpected response code: " + registerResponse.getEntity()); + assertNotNull(registerResponse.getClientId()); + assertNotNull(registerResponse.getClientSecret()); + assertNotNull(registerResponse.getRegistrationAccessToken()); + assertNotNull(registerResponse.getClientIdIssuedAt()); + assertNotNull(registerResponse.getClientSecretExpiresAt()); + + String clientId = registerResponse.getClientId(); + String clientSecret = registerResponse.getClientSecret(); + + DefaultHttpClient httpClient = createHttpClient(HostnameVerifierType.fromString(hostnameVerifier)); + CookieStore cookieStore = new BasicCookieStore(); + httpClient.setCookieStore(cookieStore); + ClientExecutor clientExecutor = new ApacheHttpClient4Executor(httpClient); + + List scopes = Arrays.asList("openid", "email"); + String nonce = UUID.randomUUID().toString(); + String state = "STATE_XYZ"; + + // 2. Request authorization (first time) + AuthorizationRequest authorizationRequest1 = new AuthorizationRequest(responseTypes, clientId, scopes, redirectUri, nonce); + authorizationRequest1.setAuthUsername(userId); + authorizationRequest1.setAuthPassword(userSecret); + authorizationRequest1.getPrompts().add(Prompt.NONE); + authorizationRequest1.setState(state); + + AuthorizeClient authorizeClient1 = new AuthorizeClient(authorizationEndpoint); + authorizeClient1.setRequest(authorizationRequest1); + AuthorizationResponse authorizationResponse1 = authorizeClient1.exec(clientExecutor); + + assertNotNull(authorizationResponse1.getLocation(), "The location is null"); + assertNotNull(authorizationResponse1.getIdToken(), "The ID Token is null"); + assertNotNull(authorizationResponse1.getAccessToken(), "The Access Token is null"); + assertNotNull(authorizationResponse1.getState(), "The state is null"); + assertNotNull(authorizationResponse1.getScope(), "The scope is null"); + + String sessionId = authorizationResponse1.getSessionId(); + + // 3. Request authorization + AuthorizationRequest authorizationRequest2 = new AuthorizationRequest(responseTypes, clientId, scopes, redirectUri, nonce); + //authorizationRequest2.setAuthUsername(userId); + //authorizationRequest2.setAuthPassword(userSecret); + authorizationRequest2.getPrompts().add(Prompt.NONE); + authorizationRequest2.setState(state); + authorizationRequest2.setSessionId(sessionId); + + JwtAuthorizationRequest jwtAuthorizationRequest = new JwtAuthorizationRequest(authorizationRequest2, SignatureAlgorithm.HS256, clientSecret); + jwtAuthorizationRequest.addUserInfoClaim(new Claim(JwtClaimName.GIVEN_NAME, ClaimValue.createNull())); + jwtAuthorizationRequest.addUserInfoClaim(new Claim(JwtClaimName.FAMILY_NAME, ClaimValue.createNull())); + jwtAuthorizationRequest.addIdTokenClaim(new Claim(JwtClaimName.SUBJECT_IDENTIFIER, ClaimValue.createSingleValue(userId))); + + String authJwt = jwtAuthorizationRequest.getEncodedJwt(); + authorizationRequest2.setRequest(authJwt); + + AuthorizeClient authorizeClient2 = new AuthorizeClient(authorizationEndpoint); + authorizeClient2.setRequest(authorizationRequest2); + AuthorizationResponse authorizationResponse2 = authorizeClient2.exec(clientExecutor); + + assertNotNull(authorizationResponse2.getLocation(), "The location is null"); + assertNotNull(authorizationResponse2.getAccessToken(), "The accessToken is null"); + assertNotNull(authorizationResponse2.getTokenType(), "The tokenType is null"); + assertNotNull(authorizationResponse2.getIdToken(), "The idToken is null"); + assertNotNull(authorizationResponse2.getState(), "The state is null"); + + String idToken = authorizationResponse2.getIdToken(); + String accessToken = authorizationResponse2.getAccessToken(); + + // 4. Validate id_token + Jwt jwt = Jwt.parse(idToken); + assertNotNull(jwt.getHeader().getClaimAsString(JwtHeaderName.TYPE)); + assertNotNull(jwt.getHeader().getClaimAsString(JwtHeaderName.ALGORITHM)); + assertNotNull(jwt.getClaims().getClaimAsString(JwtClaimName.ISSUER)); + assertNotNull(jwt.getClaims().getClaimAsString(JwtClaimName.AUDIENCE)); + assertNotNull(jwt.getClaims().getClaimAsString(JwtClaimName.EXPIRATION_TIME)); + assertNotNull(jwt.getClaims().getClaimAsString(JwtClaimName.ISSUED_AT)); + assertNotNull(jwt.getClaims().getClaimAsString(JwtClaimName.SUBJECT_IDENTIFIER)); + assertNotNull(jwt.getClaims().getClaimAsString(JwtClaimName.ACCESS_TOKEN_HASH)); + assertNotNull(jwt.getClaims().getClaimAsString(JwtClaimName.AUTHENTICATION_TIME)); + assertNotNull(jwt.getClaims().getClaimAsString(JwtClaimName.EMAIL)); + + RSAPublicKey publicKey = JwkClient.getRSAPublicKey( + jwksUri, + jwt.getHeader().getClaimAsString(JwtHeaderName.KEY_ID)); + RSASigner rsaSigner = new RSASigner(SignatureAlgorithm.RS256, publicKey); + + assertTrue(rsaSigner.validate(jwt)); + + // 5. Request user info + UserInfoClient userInfoClient = new UserInfoClient(userInfoEndpoint); + UserInfoResponse userInfoResponse = userInfoClient.execUserInfo(accessToken); + + showClient(userInfoClient); + assertEquals(userInfoResponse.getStatus(), 200, "Unexpected response code: " + userInfoResponse.getStatus()); + assertNotNull(userInfoResponse.getClaim(JwtClaimName.SUBJECT_IDENTIFIER)); + assertNotNull(userInfoResponse.getClaim(JwtClaimName.EMAIL)); + assertNotNull(userInfoResponse.getClaim(JwtClaimName.GIVEN_NAME)); + assertNotNull(userInfoResponse.getClaim(JwtClaimName.FAMILY_NAME)); + } + + @Parameters({"userId", "userSecret", "redirectUri", "redirectUris", "hostnameVerifier"}) + @Test + public void supportClaimsRequestSpecifyingSubValueFail( + final String userId, final String userSecret, final String redirectUri, final String redirectUris, + String hostnameVerifier) throws Exception { + showTitle("OC5:FeatureTest-Support claims Request Specifying sub Value (fail)"); + + List responseTypes = Arrays.asList(ResponseType.TOKEN, ResponseType.ID_TOKEN); + + // 1. Register client + RegisterRequest registerRequest = new RegisterRequest(ApplicationType.WEB, "oxAuth test app", + StringUtils.spaceSeparatedToList(redirectUris)); + registerRequest.setResponseTypes(responseTypes); + + RegisterClient registerClient = new RegisterClient(registrationEndpoint); + registerClient.setRequest(registerRequest); + RegisterResponse registerResponse = registerClient.exec(); + + showClient(registerClient); + assertEquals(registerResponse.getStatus(), 200, "Unexpected response code: " + registerResponse.getEntity()); + assertNotNull(registerResponse.getClientId()); + assertNotNull(registerResponse.getClientSecret()); + assertNotNull(registerResponse.getRegistrationAccessToken()); + assertNotNull(registerResponse.getClientIdIssuedAt()); + assertNotNull(registerResponse.getClientSecretExpiresAt()); + + String clientId = registerResponse.getClientId(); + String clientSecret = registerResponse.getClientSecret(); + + DefaultHttpClient httpClient = createHttpClient(HostnameVerifierType.fromString(hostnameVerifier)); + CookieStore cookieStore = new BasicCookieStore(); + httpClient.setCookieStore(cookieStore); + ClientExecutor clientExecutor = new ApacheHttpClient4Executor(httpClient); + + // 2. Request authorization + List scopes = Arrays.asList("openid", "email"); + String nonce = UUID.randomUUID().toString(); + String state = "af0ifjsldkj"; + + AuthorizationRequest authorizationRequest = new AuthorizationRequest(responseTypes, clientId, scopes, redirectUri, nonce); + authorizationRequest.setAuthUsername(userId); + authorizationRequest.setAuthPassword(userSecret); + authorizationRequest.getPrompts().add(Prompt.NONE); + authorizationRequest.setState(state); + + JwtAuthorizationRequest jwtAuthorizationRequest = new JwtAuthorizationRequest(authorizationRequest, SignatureAlgorithm.HS256, clientSecret); + jwtAuthorizationRequest.addUserInfoClaim(new Claim(JwtClaimName.GIVEN_NAME, ClaimValue.createNull())); + jwtAuthorizationRequest.addUserInfoClaim(new Claim(JwtClaimName.FAMILY_NAME, ClaimValue.createNull())); + jwtAuthorizationRequest.addIdTokenClaim(new Claim(JwtClaimName.SUBJECT_IDENTIFIER, ClaimValue.createSingleValue(userId))); + + String authJwt = jwtAuthorizationRequest.getEncodedJwt(); + authorizationRequest.setRequest(authJwt); + + AuthorizeClient authorizeClient = new AuthorizeClient(authorizationEndpoint); + authorizeClient.setRequest(authorizationRequest); + + AuthorizationResponse authorizationResponse = authorizeClient.exec(); + + showClient(authorizeClient); + assertEquals(authorizationResponse.getStatus(), 302, "Unexpected response code: " + authorizationResponse.getStatus()); + assertNotNull(authorizationResponse.getErrorType(), "The error type is null"); + assertEquals(authorizationResponse.getErrorType(), AuthorizeErrorResponseType.USER_MISMATCHED); + assertNotNull(authorizationResponse.getErrorDescription(), "The error description is null"); + } +} \ No newline at end of file diff --git a/Client/src/test/java/org/xdi/oxauth/interop/SupportRegistrationRead.java b/Client/src/test/java/org/xdi/oxauth/interop/SupportRegistrationRead.java new file mode 100644 index 0000000000..21974c4b18 --- /dev/null +++ b/Client/src/test/java/org/xdi/oxauth/interop/SupportRegistrationRead.java @@ -0,0 +1,96 @@ +package org.xdi.oxauth.interop; + +import org.testng.annotations.Parameters; +import org.testng.annotations.Test; +import org.xdi.oxauth.BaseTest; +import org.xdi.oxauth.client.RegisterClient; +import org.xdi.oxauth.client.RegisterRequest; +import org.xdi.oxauth.client.RegisterResponse; +import org.xdi.oxauth.model.common.AuthenticationMethod; +import org.xdi.oxauth.model.common.ResponseType; +import org.xdi.oxauth.model.common.SubjectType; +import org.xdi.oxauth.model.crypto.signature.SignatureAlgorithm; +import org.xdi.oxauth.model.register.ApplicationType; +import org.xdi.oxauth.model.util.StringUtils; + +import java.util.Arrays; +import java.util.List; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.xdi.oxauth.model.register.RegisterRequestParam.*; + +/** + * OC5:FeatureTest-Support Registration Read + * + * @author Javier Rojas Blum + * @version 1.0, 07/21/2014 + */ +public class SupportRegistrationRead extends BaseTest { + + @Parameters({"redirectUris", "redirectUri", "userId", "userSecret", "sectorIdentifierUri"}) + @Test + public void supportRegistrationRead( + final String redirectUris, final String redirectUri, final String userId, final String userSecret, + final String sectorIdentifierUri) throws Exception { + showTitle("OC5:FeatureTest-Support Registration Read"); + + List responseTypes = Arrays.asList(ResponseType.CODE); + + // 1. Register client + RegisterRequest registerRequest1 = new RegisterRequest(ApplicationType.WEB, "oxAuth test app", + StringUtils.spaceSeparatedToList(redirectUris)); + registerRequest1.setContacts(Arrays.asList("javier@gluu.org", "javier.rojas.blum@gmail.com")); + registerRequest1.setLogoUri("http://www.gluu.org/wp-content/themes/gluursn/images/logo.png"); + registerRequest1.setTokenEndpointAuthMethod(AuthenticationMethod.CLIENT_SECRET_JWT); + registerRequest1.setPolicyUri("http://www.gluu.org/policy"); + registerRequest1.setJwksUri("http://www.gluu.org/jwks"); + registerRequest1.setSectorIdentifierUri(sectorIdentifierUri); + registerRequest1.setSubjectType(SubjectType.PUBLIC); + registerRequest1.setRequestObjectSigningAlg(SignatureAlgorithm.RS256); + registerRequest1.setRequestUris(Arrays.asList("http://www.gluu.org/request")); + + RegisterClient registerClient1 = new RegisterClient(registrationEndpoint); + registerClient1.setRequest(registerRequest1); + RegisterResponse registerResponse1 = registerClient1.exec(); + + showClient(registerClient1); + assertEquals(registerResponse1.getStatus(), 200, "Unexpected response code: " + registerResponse1.getEntity()); + assertNotNull(registerResponse1.getClientId()); + assertNotNull(registerResponse1.getClientSecret()); + assertNotNull(registerResponse1.getRegistrationAccessToken()); + assertNotNull(registerResponse1.getClientSecretExpiresAt()); + assertNotNull(registerResponse1.getClaims().get(SCOPES.toString())); + + String clientId = registerResponse1.getClientId(); + String registrationAccessToken = registerResponse1.getRegistrationAccessToken(); + String registrationClientUri = registerResponse1.getRegistrationClientUri(); + + // 2. Client Read + RegisterRequest registerRequest2 = new RegisterRequest(registrationAccessToken); + + RegisterClient registerClient2 = new RegisterClient(registrationClientUri); + registerClient2.setRequest(registerRequest2); + RegisterResponse registerResponse2 = registerClient2.exec(); + + showClient(registerClient2); + assertEquals(registerResponse2.getStatus(), 200, "Unexpected response code: " + registerResponse2.getEntity()); + assertNotNull(registerResponse2.getClientId()); + assertNotNull(registerResponse2.getClientSecret()); + assertNotNull(registerResponse2.getRegistrationAccessToken()); + assertNotNull(registerResponse2.getRegistrationClientUri()); + assertNotNull(registerResponse2.getClientSecretExpiresAt()); + assertNotNull(registerResponse2.getClaims().get(APPLICATION_TYPE.toString())); + assertNotNull(registerResponse2.getClaims().get(POLICY_URI.toString())); + assertNotNull(registerResponse2.getClaims().get(REQUEST_OBJECT_SIGNING_ALG.toString())); + assertNotNull(registerResponse2.getClaims().get(CONTACTS.toString())); + assertNotNull(registerResponse2.getClaims().get(SECTOR_IDENTIFIER_URI.toString())); + assertNotNull(registerResponse2.getClaims().get(SUBJECT_TYPE.toString())); + assertNotNull(registerResponse2.getClaims().get(ID_TOKEN_SIGNED_RESPONSE_ALG.toString())); + assertNotNull(registerResponse2.getClaims().get(JWKS_URI.toString())); + assertNotNull(registerResponse2.getClaims().get(CLIENT_NAME.toString())); + assertNotNull(registerResponse2.getClaims().get(LOGO_URI.toString())); + assertNotNull(registerResponse2.getClaims().get(REQUEST_URIS.toString())); + assertNotNull(registerResponse2.getClaims().get("scopes")); + } +} \ No newline at end of file diff --git a/Client/src/test/java/org/xdi/oxauth/ws/rs/ConfigurationRestWebServiceHttpTest.java b/Client/src/test/java/org/xdi/oxauth/ws/rs/ConfigurationRestWebServiceHttpTest.java index 31956ab1d5..7e5da7b22d 100644 --- a/Client/src/test/java/org/xdi/oxauth/ws/rs/ConfigurationRestWebServiceHttpTest.java +++ b/Client/src/test/java/org/xdi/oxauth/ws/rs/ConfigurationRestWebServiceHttpTest.java @@ -42,7 +42,7 @@ public void requestOpenIdConfiguration() throws Exception { assertTrue(response.getScopeToClaimsMapping().size() > 0, "The scope to claims mapping is empty"); assertTrue(response.getResponseTypesSupported().size() > 0, "The responseTypesSupported is empty"); assertTrue(response.getGrantTypesSupported().size() > 0, "The grantTypesSupported is empty"); - assertTrue(response.getAcrValuesSupported().size() > 0, "The acrValuesSupported is empty"); + assertTrue(response.getAcrValuesSupported().size() == 0, "The acrValuesSupported is not empty"); assertTrue(response.getAmrValuesSupported().size() > 0, "The amrValuesSupported is empty"); assertTrue(response.getSubjectTypesSupported().size() > 0, "The subjectTypesSupported is empty"); assertTrue(response.getUserInfoSigningAlgValuesSupported().size() > 0, "The userInfoSigningAlgValuesSupported is empty"); diff --git a/Client/src/test/java/org/xdi/oxauth/ws/rs/RegistrationRestWebServiceHttpTest.java b/Client/src/test/java/org/xdi/oxauth/ws/rs/RegistrationRestWebServiceHttpTest.java index 8b39691913..6702b37ed7 100644 --- a/Client/src/test/java/org/xdi/oxauth/ws/rs/RegistrationRestWebServiceHttpTest.java +++ b/Client/src/test/java/org/xdi/oxauth/ws/rs/RegistrationRestWebServiceHttpTest.java @@ -14,7 +14,9 @@ import org.xdi.oxauth.model.util.StringUtils; import javax.ws.rs.HttpMethod; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import static org.testng.Assert.*; import static org.xdi.oxauth.model.register.RegisterRequestParam.*; @@ -57,7 +59,7 @@ public void requestClientAssociate2(final String redirectUris, final String sect RegisterRequest registerRequest = new RegisterRequest(ApplicationType.WEB, "oxAuth test app", StringUtils.spaceSeparatedToList(redirectUris)); registerRequest.setContacts(Arrays.asList("javier@gluu.org", "javier.rojas.blum@gmail.com")); - registerRequest.setScopes(Arrays.asList("openid", "clientinfo", "profile", "email", "invalid_scope")); + registerRequest.setScopes(Arrays.asList("openid", "address", "profile", "email", "phone", "clientinfo", "invalid_scope")); registerRequest.setLogoUri("http://www.gluu.org/wp-content/themes/gluursn/images/logo.png"); registerRequest.setTokenEndpointAuthMethod(AuthenticationMethod.CLIENT_SECRET_JWT); registerRequest.setPolicyUri("http://www.gluu.org/policy"); @@ -79,10 +81,16 @@ public void requestClientAssociate2(final String redirectUris, final String sect assertNotNull(response.getClientSecretExpiresAt()); assertNotNull(response.getClaims().get(SCOPES.toString())); JSONArray scopesJsonArray = new JSONArray(response.getClaims().get(SCOPES.toString())); - assertEquals(scopesJsonArray.get(0), "openid"); - assertEquals(scopesJsonArray.get(1), "clientinfo"); - assertEquals(scopesJsonArray.get(2), "profile"); - assertEquals(scopesJsonArray.get(3), "email"); + List scopes = new ArrayList(); + for (int i = 0; i < scopesJsonArray.length(); i++) { + scopes.add(scopesJsonArray.get(i).toString()); + } + assertTrue(scopes.contains("openid")); + assertTrue(scopes.contains("address")); + assertTrue(scopes.contains("email")); + assertTrue(scopes.contains("profile")); + assertTrue(scopes.contains("phone")); + assertTrue(scopes.contains("clientinfo")); clientId1 = response.getClientId(); registrationAccessToken1 = response.getRegistrationAccessToken(); diff --git a/Client/src/test/java/org/xdi/oxauth/ws/rs/UserInfoRestWebServiceHttpTest.java b/Client/src/test/java/org/xdi/oxauth/ws/rs/UserInfoRestWebServiceHttpTest.java index 389fd0dfde..f8c6e408da 100644 --- a/Client/src/test/java/org/xdi/oxauth/ws/rs/UserInfoRestWebServiceHttpTest.java +++ b/Client/src/test/java/org/xdi/oxauth/ws/rs/UserInfoRestWebServiceHttpTest.java @@ -189,11 +189,11 @@ public void requestUserInfoInsufficientScope(final String userId, final String u assertNotNull(authorizationResponse.getScope(), "The scope must be null"); assertNotNull(authorizationResponse.getIdToken(), "The id token must be null"); - String idToken = authorizationResponse.getIdToken(); + String accessToken = authorizationResponse.getAccessToken(); // 2. Request user info UserInfoClient userInfoClient = new UserInfoClient(userInfoEndpoint); - UserInfoResponse userInfoResponse = userInfoClient.execUserInfo(idToken); + UserInfoResponse userInfoResponse = userInfoClient.execUserInfo(accessToken); showClient(userInfoClient); assertEquals(userInfoResponse.getStatus(), 403, "Unexpected response code: " + userInfoResponse.getStatus()); diff --git a/Client/src/test/resources/testng.xml b/Client/src/test/resources/testng.xml index 795bec4ceb..4cdd49d814 100644 --- a/Client/src/test/resources/testng.xml +++ b/Client/src/test/resources/testng.xml @@ -3,77 +3,77 @@ - + - + - + - + - + - + - + - + - + - + - + @@ -87,66 +87,66 @@ - + - + - + - + - + - + - + - + - + - + @@ -154,7 +154,7 @@ - + @@ -169,7 +169,7 @@ - + @@ -189,7 +189,7 @@ - + @@ -537,14 +537,19 @@ + + + + + - + - + diff --git a/Model/pom.xml b/Model/pom.xml index c3e0aea2db..c37942af6b 100644 --- a/Model/pom.xml +++ b/Model/pom.xml @@ -9,7 +9,7 @@ org.xdi oxauth - 1.3.2.Final + 1.4.1.Final diff --git a/Model/src/main/java/org/xdi/oxauth/model/authorize/AuthorizeRequestParam.java b/Model/src/main/java/org/xdi/oxauth/model/authorize/AuthorizeRequestParam.java index b216a1ac19..7afdf649fb 100644 --- a/Model/src/main/java/org/xdi/oxauth/model/authorize/AuthorizeRequestParam.java +++ b/Model/src/main/java/org/xdi/oxauth/model/authorize/AuthorizeRequestParam.java @@ -21,8 +21,10 @@ public interface AuthorizeRequestParam { public static final String ID_TOKEN_HINT = "id_token_hint"; public static final String LOGIN_HINT = "login_hint"; public static final String ACR_VALUES = "acr_values"; + public static final String AMR_VALUES = "amr_values"; public static final String CLAIMS = "claims"; public static final String REGISTRATION = "registration"; public static final String REQUEST = "request"; public static final String REQUEST_URI = "request_uri"; + public static final String ORIGIN_HEADERS = "origin_headers"; } \ No newline at end of file diff --git a/Model/src/main/java/org/xdi/oxauth/model/util/Util.java b/Model/src/main/java/org/xdi/oxauth/model/util/Util.java index dadfb584dd..eccb603817 100644 --- a/Model/src/main/java/org/xdi/oxauth/model/util/Util.java +++ b/Model/src/main/java/org/xdi/oxauth/model/util/Util.java @@ -100,4 +100,16 @@ public static List splittedStringAsList(String p_string, String p_delimi } return result; } + + public static List jsonArrayStringAsList(String jsonString) throws JSONException { + final List result = new ArrayList(); + if (StringUtils.isNotBlank(jsonString)) { + JSONArray jsonArray = new JSONArray(jsonString); + + return asList(jsonArray); + } + + return result; + } + } diff --git a/RP/pom.xml b/RP/pom.xml index 470f52ac74..71f8d4b066 100644 --- a/RP/pom.xml +++ b/RP/pom.xml @@ -9,7 +9,7 @@ org.xdi oxauth - 1.3.2.Final + 1.4.1.Final diff --git a/Server/conf/oxauth-config.xml b/Server/conf/oxauth-config.xml index 3652a58d18..3c671c3a32 100644 --- a/Server/conf/oxauth-config.xml +++ b/Server/conf/oxauth-config.xml @@ -44,16 +44,13 @@ urn:ietf:params:oauth:grant-type:jwt-bearer - http://example.com/authn/auth_mode/duo - http://example.com/authn/auth_level/10 - http://example.com/authn/auth_mode/toopher - duo - 10 - toopher + https://schema.gluu.org/openid/amr/method/duo + https://schema.gluu.org/openid/amr/level/10 + https://schema.gluu.org/openid/amr/method/toopher public diff --git a/Server/integrations/saml/README.txt b/Server/integrations/saml/README.txt index cd903e3f99..9966cf7b8a 100644 --- a/Server/integrations/saml/README.txt +++ b/Server/integrations/saml/README.txt @@ -35,7 +35,7 @@ This module has next properties: should map 'Persistent Id' to local user account. If this property has 'enroll' value Saml script should add new user to local LDAP with status 'register'. In order to map IDP attributes to local attributes it uses propertiessaml_idp_attributes_list and saml_local_attributes_list. - Allowed values: map/enroll + Allowed values: map/enroll/enroll_all_attr Example: enroll 7) saml_validate_response - Specify if Saml script should valide Saml response signature. The path to IdP certificate should be specified in @@ -70,3 +70,5 @@ This module has next properties: return True/False Saml scripts calls init method at initialization. And calls postLogin after user log in order to execute additional custom workflow. +12) saml_allow_basic_login - Specify if authentication module should allow both: basic and saml authentications + Example: false diff --git a/Server/integrations/saml/SamlExternalAuthenticator.py b/Server/integrations/saml/SamlExternalAuthenticator.py index f050d30f2b..338443c686 100644 --- a/Server/integrations/saml/SamlExternalAuthenticator.py +++ b/Server/integrations/saml/SamlExternalAuthenticator.py @@ -2,18 +2,14 @@ from org.jboss.seam.security import Identity from javax.faces.context import FacesContext from org.xdi.oxauth.service.python.interfaces import ExternalAuthenticatorType -from org.xdi.oxauth.service import UserService -from org.xdi.oxauth.service import ClientService -from org.xdi.oxauth.service import AuthenticationService +from org.xdi.oxauth.service import UserService, ClientService, AuthenticationService, AttributeService from org.xdi.oxauth.service.net import HttpService from org.xdi.util.security import StringEncrypter from org.xdi.util import StringHelper from org.xdi.util import ArrayHelper from org.gluu.saml import SamlConfiguration, AuthRequest, Response -from java.util import Arrays -from java.util import HashMap -from java.util import IdentityHashMap -from org.xdi.oxauth.model.common import User +from java.util import Arrays, ArrayList, HashMap, IdentityHashMap +from org.xdi.oxauth.model.common import User, CustomAttribute import java @@ -112,6 +108,7 @@ def authenticate(self, configurationAttributes, requestParameters, step): saml_map_user = False saml_enroll_user = False + saml_enroll_all_user_attr = False # Use saml_deployment_type only if there is no attributes mapping if (configurationAttributes.containsKey("saml_deployment_type")): saml_deployment_type = StringHelper.toLowerCase(configurationAttributes.get("saml_deployment_type").getValue2()) @@ -122,6 +119,38 @@ def authenticate(self, configurationAttributes, requestParameters, step): if (StringHelper.equalsIgnoreCase(saml_deployment_type, "enroll")): saml_enroll_user = True + if (StringHelper.equalsIgnoreCase(saml_deployment_type, "enroll_all_attr")): + saml_enroll_all_user_attr = True + + saml_allow_basic_login = False + if (configurationAttributes.containsKey("saml_allow_basic_login")): + saml_allow_basic_login = StringHelper.toBoolean(configurationAttributes.get("saml_allow_basic_login").getValue2(), False) + + use_basic_auth = False + if (saml_allow_basic_login): + basic_auth = requestParameters.get("basic_auth") + if (ArrayHelper.isNotEmpty(basic_auth)): + use_basic_auth = StringHelper.toBoolean(basic_auth[0], False) + + if ((step == 1) and saml_allow_basic_login and use_basic_auth): + print "Saml authenticate for step 1. Basic authentication" + + context.set("saml_count_login_steps", 1) + + credentials = Identity.instance().getCredentials() + user_name = credentials.getUsername() + user_password = credentials.getPassword() + + logged_in = False + if (StringHelper.isNotEmptyString(user_name) and StringHelper.isNotEmptyString(user_password)): + userService = UserService.instance() + logged_in = userService.authenticate(user_name, user_password) + + if (not logged_in): + return False + + return True + if (step == 1): print "Saml authenticate for step 1" @@ -226,6 +255,45 @@ def authenticate(self, configurationAttributes, requestParameters, step): find_user_by_uid = userService.addUser(newUser) print "Saml authenticate for step 1. Added new user with UID", find_user_by_uid.getUserId() + elif (saml_enroll_all_user_attr): + print "Saml authenticate for step 1. Attempting to find user by oxExternalUid: saml:" + saml_user_uid + + # Check if the is user with specified saml_user_uid + find_user_by_uid = userService.getUserByAttribute("oxExternalUid", "saml:" + saml_user_uid) + + if (find_user_by_uid == None): + print "Saml authenticate for step 1. Failed to find user" + + user = User() + customAttributes = ArrayList() + for key in attributes.keySet(): + ldapAttributes = attributeService.getAllAttributes() + for ldapAttribute in ldapAttributes: + saml2Uri = ldapAttribute.getSaml2Uri() + if(saml2Uri == None): + saml2Uri = attributeService.getDefaultSaml2Uri(ldapAttribute.getName()) + if(saml2Uri == key): + attribute = CustomAttribute(ldapAttribute.getName()) + attribute.setValues(attributes.get(key)) + customAttributes.add(attribute) + + attribute = CustomAttribute("oxExternalUid") + attribute.setValue("saml:" + saml_user_uid) + customAttributes.add(attribute) + user.setCustomAttributes(customAttributes) + + if(user.getAttribute("sn") == None): + attribute = CustomAttribute("sn") + attribute.setValue(saml_user_uid) + customAttributes.add(attribute) + + if(user.getAttribute("cn") == None): + attribute = CustomAttribute("cn") + attribute.setValue(saml_user_uid) + customAttributes.add(attribute) + + find_user_by_uid = userService.addUser(user) + print "Saml authenticate for step 1. Added new user with UID", find_user_by_uid.getUserId() found_user_name = find_user_by_uid.getUserId() print "Saml authenticate for step 1. found_user_name:", found_user_name @@ -370,7 +438,15 @@ def getCountAuthenticationSteps(self, configurationAttributes): def getPageForStep(self, configurationAttributes, step): if (step == 1): - return "/auth/saml/samllogin.xhtml" + saml_allow_basic_login = False + if (configurationAttributes.containsKey("saml_allow_basic_login")): + saml_allow_basic_login = StringHelper.toBoolean(configurationAttributes.get("saml_allow_basic_login").getValue2(), False) + + if (saml_allow_basic_login): + return "/login.xhtml" + else: + return "/auth/saml/samllogin.xhtml" + return "/auth/saml/samlpostlogin.xhtml" def logout(self, configurationAttributes, requestParameters): diff --git a/Server/pom.xml b/Server/pom.xml index bea10c687b..c36fbd8fac 100644 --- a/Server/pom.xml +++ b/Server/pom.xml @@ -10,7 +10,7 @@ org.xdi oxauth - 1.3.2.Final + 1.4.1.Final @@ -246,6 +246,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -553,6 +583,14 @@ javax.servlet servlet-api + + com.wordnik + swagger-jaxrs_2.10 + + + com.wordnik + swagger-servlet_2.9.1 + diff --git a/Server/src/main/docs/mustache/markdown.mustache b/Server/src/main/docs/mustache/markdown.mustache new file mode 100644 index 0000000000..4e395468f4 --- /dev/null +++ b/Server/src/main/docs/mustache/markdown.mustache @@ -0,0 +1,112 @@ +## API Document + +{{#apiDocuments}} +### {{resourcePath}} + +#### Overview +{{{description}}} + +{{#apis}} +#### `{{path}}` +{{#operations}} +##### {{nickname}} +**{{httpMethod}}** `{{path}}` + +{{summary}} +{{{notes}}} + +###### URL + {{url}} +###### Parameters +{{#parameters}} +- {{paramType}} + + + + + + + + + {{#paras}} + + + + + + + {{/paras}} +
ParameterRequiredDescriptionData Type
{{name}}{{required}}{{description}}{{#linkType}}{{type}}{{/linkType}}{{^linkType}}{{type}}{{/linkType}}
+{{/parameters}} + +{{#responseClass}} +###### Response +[{{className}}](#{{classLinkName}}){{^genericClasses}}{{/genericClasses}}{{#genericClasses}}< [{{className}}](#{{classLinkName}}) >{{/genericClasses}} +{{/responseClass}} + + +###### Errors + + + + + + {{#errorResponses}} + + + + + {{/errorResponses}} +
Status CodeReason
{{code}}{{message}}
+ +{{#samples}} +###### Samples +{{/samples}} +{{#samples}} +{{sampleDescription}} + +- Sample Request + +``` +{{{sampleRequest}}} +``` + +- Sample Response + +``` +{{{sampleResponse}}} +``` + +{{/samples}} + +- - - +{{/operations}} +{{/apis}} +{{/apiDocuments}} + +## Data Types +{{#dataTypes}} + + +## {{name}} + + + + + + + + + + {{#items}} + + + + + + + + {{/items}} +
typerequiredaccessdescriptionnotes
{{#linkType}}{{type}}{{/linkType}}{{^linkType}}{{type}}{{/linkType}}{{#required}}required{{/required}}{{^required}}optional{{/required}}{{#access}}{{{access}}}{{/access}}{{^access}}-{{/access}}{{#description}}{{{description}}}{{/description}}{{^description}}-{{/description}}{{#notes}}{{{notes}}}{{/notes}}{{^notes}}-{{/notes}}
+ +{{/dataTypes}} diff --git a/Server/src/main/java/org/xdi/oxauth/auth/Authenticator.java b/Server/src/main/java/org/xdi/oxauth/auth/Authenticator.java index 1000ba9d35..71987bc39d 100644 --- a/Server/src/main/java/org/xdi/oxauth/auth/Authenticator.java +++ b/Server/src/main/java/org/xdi/oxauth/auth/Authenticator.java @@ -348,6 +348,11 @@ public String prepareAuthenticationForStep() { // Redirect user to alternative login workflow String redirectTo = externalAuthenticationService.executeExternalAuthenticatorGetPageForStep( externalAuthenticatorConfiguration, this.authStep); + + if (StringHelper.isEmpty(redirectTo)) { + redirectTo = "/login.xhtml"; + } + log.debug( "Redirect to page: {0}. Force to use auth_mode: '{1}'", redirectTo, determinedAuthMode); diff --git a/Server/src/main/java/org/xdi/oxauth/authorize/ws/rs/AuthorizeAction.java b/Server/src/main/java/org/xdi/oxauth/authorize/ws/rs/AuthorizeAction.java index 85c427f61b..bba494429e 100644 --- a/Server/src/main/java/org/xdi/oxauth/authorize/ws/rs/AuthorizeAction.java +++ b/Server/src/main/java/org/xdi/oxauth/authorize/ws/rs/AuthorizeAction.java @@ -1,6 +1,7 @@ package org.xdi.oxauth.authorize.ws.rs; import org.apache.commons.lang.StringUtils; +import org.codehaus.jettison.json.JSONException; import org.jboss.seam.Component; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.In; @@ -33,8 +34,10 @@ import org.xdi.oxauth.service.*; import org.xdi.util.StringHelper; +import javax.faces.context.ExternalContext; import javax.faces.context.FacesContext; import javax.servlet.http.HttpServletRequest; + import java.io.UnsupportedEncodingException; import java.util.*; @@ -47,7 +50,7 @@ public class AuthorizeAction { public static final List ALLOWED_PARAMETER = Collections.unmodifiableList(Arrays.asList( "scope", "response_type", "client_id", "redirect_uri", "state", "nonce", "display", "prompt", "max_age", - "ui_locales", "id_token_hint", "login_hint", "acr_values", "session_id", "request", "request_uri")); + "ui_locales", "id_token_hint", "login_hint", "acr_values", "amr_values", "session_id", "request", "request_uri")); @Logger private Log log; @@ -110,6 +113,7 @@ public class AuthorizeAction { private String idTokenHint; private String loginHint; private String acrValues; + private String amrValues; private String request; private String requestUri; @@ -151,16 +155,34 @@ private SessionId getSession() { } public void checkPermissionGranted() { + final ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext(); + final SessionId session = getSession(); + authenticationService.storeRequestHeadersInSession((HttpServletRequest) externalContext.getRequest()); if (session == null || session.getUserDn() == null) { - Map parameterMap = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap(); + Map parameterMap = externalContext.getRequestParameterMap(); String redirectTo = "/login.xhtml"; boolean useExternalAuthenticator = externalAuthenticationService.isEnabled(AuthenticationScriptUsageType.INTERACTIVE); if (useExternalAuthenticator) { - ExternalAuthenticatorConfiguration externalAuthenticatorConfiguration = externalAuthenticationService.determineExternalAuthenticatorConfiguration(AuthenticationScriptUsageType.INTERACTIVE, 1, this.authLevel, this.authMode); + + List amrValuesList = null; + try { + amrValuesList = Util.jsonArrayStringAsList(amrValues); + } catch (JSONException ex) { + invalidRequest(); + return; + } + + ExternalAuthenticatorConfiguration externalAuthenticatorConfiguration; + + if ((amrValuesList != null) && !amrValuesList.isEmpty()) { + externalAuthenticatorConfiguration = externalAuthenticationService.determineExternalAuthenticatorConfiguration(AuthenticationScriptUsageType.INTERACTIVE, amrValuesList); + } else { + externalAuthenticatorConfiguration = externalAuthenticationService.determineExternalAuthenticatorConfiguration(AuthenticationScriptUsageType.INTERACTIVE, 1, this.authLevel, this.authMode); + } if (externalAuthenticatorConfiguration == null) { log.error("Failed to get ExternalAuthenticatorConfiguration. auth_step: {0}, auth_mode: {1}, auth_level: {2}", 1, authMode, authLevel); @@ -532,7 +554,15 @@ public void setAcrValues(String acrValues) { this.acrValues = acrValues; } - /** + public String getAmrValues() { + return amrValues; + } + + public void setAmrValues(String amrValues) { + this.amrValues = amrValues; + } + + /** * Returns a JWT encoded OpenID Request Object. * * @return A JWT encoded OpenID Request Object. diff --git a/Server/src/main/java/org/xdi/oxauth/authorize/ws/rs/AuthorizeRestWebService.java b/Server/src/main/java/org/xdi/oxauth/authorize/ws/rs/AuthorizeRestWebService.java index 2b9c10b676..282a6828d1 100644 --- a/Server/src/main/java/org/xdi/oxauth/authorize/ws/rs/AuthorizeRestWebService.java +++ b/Server/src/main/java/org/xdi/oxauth/authorize/ws/rs/AuthorizeRestWebService.java @@ -1,5 +1,7 @@ package org.xdi.oxauth.authorize.ws.rs; +import com.wordnik.swagger.annotations.Api; + import javax.servlet.http.HttpServletRequest; import javax.ws.rs.*; import javax.ws.rs.core.Context; @@ -20,6 +22,7 @@ * @author Javier Rojas Blum Date: 09.20.2011 */ @Path("/oxauth") +@Api(value = "/oxauth", description = "The Authorization Endpoint performs Authentication of the End-User. This is done by sending the User Agent to the Authorization Server's Authorization Endpoint for Authentication and Authorization, using request parameters defined by OAuth 2.0 and additional parameters and parameter values defined by OpenID Connect.") public interface AuthorizeRestWebService { /** @@ -53,6 +56,11 @@ public interface AuthorizeRestWebService { * @param acrValues Requested Authentication Context Class Reference values. Space-separated string that * specifies the acr values that the Authorization Server is being requested to use for * processing this Authentication Request, with the values appearing in order of preference. + * @param amrValues Requested Authentication Methods References. JSON array of strings that are identifiers + * for authentication methods used in the authentication. For instance, values might indicate + * that both password and OTP authentication methods were used. The definition of particular + * values to be used in the amr Claim is beyond the scope of this specification.The amr value + * is an array of case sensitive strings. * @param request A JWT encoded OpenID Request Object. * @param requestUri An URL that points to an OpenID Request Object. * @param requestSessionId @@ -127,6 +135,7 @@ Response requestAuthorizationGet( @QueryParam("id_token_hint") String idTokenHint, @QueryParam("login_hint") String loginHint, @QueryParam("acr_values") String acrValues, + @QueryParam("amr_values") String amrValues, @QueryParam("request") String request, @QueryParam("request_uri") String requestUri, @QueryParam("request_session_id") String requestSessionId, @@ -134,6 +143,7 @@ Response requestAuthorizationGet( @QueryParam("access_token") String accessToken, @QueryParam("auth_level") String authLevel, @QueryParam("auth_mode") String authMode, + @QueryParam("origin_headers") String originHeaders, @Context HttpServletRequest httpRequest, @Context SecurityContext securityContext); @@ -155,6 +165,7 @@ Response requestAuthorizationPost( @FormParam("id_token_hint") String idTokenHint, @FormParam("login_hint") String loginHint, @FormParam("acr_values") String acrValues, + @FormParam("amr_values") String amrValues, @FormParam("request") String request, @FormParam("request_uri") String requestUri, @FormParam("request_session_id") String requestSessionId, @@ -162,6 +173,7 @@ Response requestAuthorizationPost( @FormParam("access_token") String accessToken, @FormParam("auth_level") String authLevel, @FormParam("auth_mode") String authMode, + @FormParam("origin_headers") String originHeaders, @Context HttpServletRequest httpRequest, @Context SecurityContext securityContext); } \ No newline at end of file diff --git a/Server/src/main/java/org/xdi/oxauth/authorize/ws/rs/AuthorizeRestWebServiceImpl.java b/Server/src/main/java/org/xdi/oxauth/authorize/ws/rs/AuthorizeRestWebServiceImpl.java index eaf55afc27..c8ba84961a 100644 --- a/Server/src/main/java/org/xdi/oxauth/authorize/ws/rs/AuthorizeRestWebServiceImpl.java +++ b/Server/src/main/java/org/xdi/oxauth/authorize/ws/rs/AuthorizeRestWebServiceImpl.java @@ -1,6 +1,30 @@ package org.xdi.oxauth.authorize.ws.rs; +import static org.xdi.oxauth.model.util.StringUtils.implode; +import static org.xdi.oxauth.model.util.StringUtils.toJSONArray; + +import java.net.ConnectException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.UnknownHostException; +import java.security.SignatureException; +import java.util.Calendar; +import java.util.Collection; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TimeZone; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.HttpMethod; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.ResponseBuilder; +import javax.ws.rs.core.SecurityContext; + import org.apache.commons.lang.StringUtils; +import org.codehaus.jettison.json.JSONException; import org.gluu.site.ldap.persistence.exception.EntryPersistenceException; import org.jboss.resteasy.client.ClientRequest; import org.jboss.resteasy.client.ClientResponse; @@ -12,8 +36,23 @@ import org.jboss.seam.security.Identity; import org.xdi.model.GluuAttribute; import org.xdi.oxauth.auth.Authenticator; -import org.xdi.oxauth.model.authorize.*; -import org.xdi.oxauth.model.common.*; +import org.xdi.oxauth.model.authorize.AuthorizeErrorResponseType; +import org.xdi.oxauth.model.authorize.AuthorizeParamsValidator; +import org.xdi.oxauth.model.authorize.AuthorizeRequestParam; +import org.xdi.oxauth.model.authorize.Claim; +import org.xdi.oxauth.model.authorize.JwtAuthorizationRequest; +import org.xdi.oxauth.model.common.AccessToken; +import org.xdi.oxauth.model.common.AuthorizationCode; +import org.xdi.oxauth.model.common.AuthorizationGrant; +import org.xdi.oxauth.model.common.AuthorizationGrantList; +import org.xdi.oxauth.model.common.IdToken; +import org.xdi.oxauth.model.common.Parameters; +import org.xdi.oxauth.model.common.Prompt; +import org.xdi.oxauth.model.common.ResponseMode; +import org.xdi.oxauth.model.common.ResponseType; +import org.xdi.oxauth.model.common.Scope; +import org.xdi.oxauth.model.common.SessionId; +import org.xdi.oxauth.model.common.User; import org.xdi.oxauth.model.config.ClaimMappingConfiguration; import org.xdi.oxauth.model.config.ConfigurationFactory; import org.xdi.oxauth.model.error.ErrorResponseFactory; @@ -23,7 +62,15 @@ import org.xdi.oxauth.model.registration.Client; import org.xdi.oxauth.model.util.JwtUtil; import org.xdi.oxauth.model.util.Util; -import org.xdi.oxauth.service.*; +import org.xdi.oxauth.service.AttributeService; +import org.xdi.oxauth.service.AuthenticationFilterService; +import org.xdi.oxauth.service.ClientService; +import org.xdi.oxauth.service.FederationDataService; +import org.xdi.oxauth.service.RedirectionUriService; +import org.xdi.oxauth.service.ScopeService; +import org.xdi.oxauth.service.SessionIdService; +import org.xdi.oxauth.service.UserGroupService; +import org.xdi.oxauth.service.UserService; import org.xdi.oxauth.util.QueryStringDecoder; import org.xdi.oxauth.util.RedirectUri; import org.xdi.oxauth.util.RedirectUtil; @@ -31,19 +78,7 @@ import org.xdi.util.StringHelper; import org.xdi.util.security.StringEncrypter; -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.HttpMethod; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.ResponseBuilder; -import javax.ws.rs.core.SecurityContext; -import java.net.ConnectException; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.UnknownHostException; -import java.security.SignatureException; -import java.util.*; - -import static org.xdi.oxauth.model.util.StringUtils.implode; +import com.wordnik.swagger.annotations.Api; /** * Implementation for request authorization through REST web services. @@ -52,14 +87,12 @@ * @version 0.9, 08/14/2014 */ @Name("requestAuthorizationRestWebService") +@Api(value = "/oxauth/authorize", description = "Authorization Endpointt") public class AuthorizeRestWebServiceImpl implements AuthorizeRestWebService { @Logger private Log log; - @In - private AuthenticationService authenticationService; - @In private ErrorResponseFactory errorResponseFactory; @@ -103,31 +136,31 @@ public class AuthorizeRestWebServiceImpl implements AuthorizeRestWebService { public Response requestAuthorizationGet( String scope, String responseType, String clientId, String redirectUri, String state, String responseMode, String nonce, String display, String prompt, Integer maxAge, String uiLocales, String idTokenHint, - String loginHint, String acrValues, String request, String requestUri, String requestSessionId, - String sessionId, String accessToken, String authLevel, String authMode, HttpServletRequest httpRequest, + String loginHint, String acrValues, String amrValues, String request, String requestUri, String requestSessionId, + String sessionId, String accessToken, String authLevel, String authMode, String originHeaders, HttpServletRequest httpRequest, SecurityContext securityContext) { return requestAuthorization(scope, responseType, clientId, redirectUri, state, responseMode, nonce, display, - prompt, maxAge, uiLocales, idTokenHint, loginHint, acrValues, request, requestUri, requestSessionId, - sessionId, accessToken, authLevel, authMode, HttpMethod.GET, httpRequest, securityContext); + prompt, maxAge, uiLocales, idTokenHint, loginHint, acrValues, amrValues, request, requestUri, requestSessionId, + sessionId, accessToken, authLevel, authMode, HttpMethod.GET, originHeaders, httpRequest, securityContext); } @Override public Response requestAuthorizationPost( String scope, String responseType, String clientId, String redirectUri, String state, String responseMode, String nonce, String display, String prompt, Integer maxAge, String uiLocales, String idTokenHint, - String loginHint, String acrValues, String request, String requestUri, String requestSessionId, - String sessionId, String accessToken, String authLevel, String authMode, HttpServletRequest httpRequest, + String loginHint, String acrValues, String amrValues, String request, String requestUri, String requestSessionId, + String sessionId, String accessToken, String authLevel, String authMode, String originHeaders, HttpServletRequest httpRequest, SecurityContext securityContext) { return requestAuthorization(scope, responseType, clientId, redirectUri, state, responseMode, nonce, display, - prompt, maxAge, uiLocales, idTokenHint, loginHint, acrValues, request, requestUri, requestSessionId, - sessionId, accessToken, authLevel, authMode, HttpMethod.POST, httpRequest, securityContext); + prompt, maxAge, uiLocales, idTokenHint, loginHint, acrValues, amrValues, request, requestUri, requestSessionId, + sessionId, accessToken, authLevel, authMode, HttpMethod.POST, originHeaders, httpRequest, securityContext); } public Response requestAuthorization( String scope, String responseType, String clientId, String redirectUri, String state, String respMode, String nonce, String display, String prompt, Integer maxAge, String uiLocalesStr, String idTokenHint, - String loginHint, String acrValuesStr, String request, String requestUri, String requestSessionId, - String sessionId, String accessToken, String authLevel, String authMode, String method, + String loginHint, String acrValuesStr, String amrValuesStr, String request, String requestUri, String requestSessionId, + String sessionId, String accessToken, String authLevel, String authMode, String method, String originHeaders, HttpServletRequest httpRequest, SecurityContext securityContext) { scope = ServerUtil.urlDecode(scope); // it may be encoded in uma case @@ -140,7 +173,7 @@ public Response requestAuthorization( state, request, securityContext.isSecure(), requestSessionId, sessionId); log.debug("Attempting to request authorization: " - + "authLevel = {0}, authMode = {1}", authLevel, authMode); + + "acrValues = {0}, amrValues = {1}, authLevel = {2}, authMode = {3}, originHeaders = {4}", acrValuesStr, amrValuesStr, authLevel, authMode, originHeaders); ResponseBuilder builder = Response.ok(); @@ -153,7 +186,14 @@ public Response requestAuthorization( List prompts = Prompt.fromString(prompt, " "); List scopes = Util.splittedStringAsList(scope, " "); List acrValues = Util.splittedStringAsList(acrValuesStr, " "); - ResponseMode responseMode = ResponseMode.getByValue(respMode); + List amrValues = null; + try { + amrValues = Util.jsonArrayStringAsList(amrValuesStr); + } catch (JSONException ex) { + log.error(ex.getMessage(), ex); + } + + ResponseMode responseMode = ResponseMode.getByValue(respMode); User user = sessionUser != null && StringUtils.isNotBlank(sessionUser.getUserDn()) ? userService.getUserByDn(sessionUser.getUserDn()) : null; @@ -371,7 +411,7 @@ public Response requestAuthorization( redirectToAuthorizationPage(redirectUriResponse, responseTypes, scope, clientId, redirectUri, state, nonce, display, prompts, maxAge, uiLocales, - idTokenHint, loginHint, acrValues, request, requestUri); + idTokenHint, loginHint, acrValues, amrValues, request, requestUri, originHeaders); builder = RedirectUtil.getRedirectResponseBuilder(redirectUriResponse.toString(), httpRequest); return builder.build(); } @@ -391,7 +431,7 @@ public Response requestAuthorization( redirectToAuthorizationPage(redirectUriResponse, responseTypes, scope, clientId, redirectUri, state, nonce, display, prompts, maxAge, uiLocales, idTokenHint, - loginHint, acrValues, request, requestUri); + loginHint, acrValues, amrValues, request, requestUri, originHeaders); builder = RedirectUtil.getRedirectResponseBuilder(redirectUriResponse.toString(), httpRequest); return builder.build(); } @@ -401,7 +441,7 @@ public Response requestAuthorization( redirectToAuthorizationPage(redirectUriResponse, responseTypes, scope, clientId, redirectUri, state, nonce, display, prompts, maxAge, uiLocales, idTokenHint, - loginHint, acrValues, request, requestUri); + loginHint, acrValues, amrValues, request, requestUri, originHeaders); builder = RedirectUtil.getRedirectResponseBuilder(redirectUriResponse.toString(), httpRequest); return builder.build(); } @@ -434,7 +474,7 @@ public Response requestAuthorization( redirectToAuthorizationPage(redirectUriResponse, responseTypes, scope, clientId, redirectUri, state, nonce, display, prompts, maxAge, uiLocales, idTokenHint, - loginHint, acrValues, request, requestUri); + loginHint, acrValues, amrValues, request, requestUri, originHeaders); builder = RedirectUtil.getRedirectResponseBuilder(redirectUriResponse.toString(), httpRequest); return builder.build(); } @@ -488,10 +528,10 @@ public Response requestAuthorization( // Store authentication level and mode authorizationGrant.setAuthLevel(authLevel); authorizationGrant.setAuthMode(authMode); - authorizationGrant.save(); // call save after object modification!!! + authorizationGrant.save(); // call save after object modification, call is asynchronous!!! } Map idTokenClaims = getClaims(user, authorizationGrant, scopes); - IdToken idToken = authorizationGrant.createIdToken(nonce, authorizationCode, newAccessToken, idTokenClaims); + IdToken idToken = authorizationGrant.createIdToken(nonce, authorizationCode, newAccessToken, idTokenClaims, authorizationGrant.getAuthLevel(), authorizationGrant.getAuthMode()); redirectUriResponse.addResponseParameter("id_token", idToken.getCode()); } @@ -564,8 +604,8 @@ private ResponseBuilder error(Response.Status p_status, AuthorizeErrorResponseTy private void redirectToAuthorizationPage( RedirectUri redirectUriResponse, List responseTypes, String scope, String clientId, String redirectUri, String state, String nonce, String display, List prompts, Integer maxAge, - List uiLocales, String idTokenHint, String loginHint, List acrValues, String request, - String requestUri) { + List uiLocales, String idTokenHint, String loginHint, List acrValues, List amrValues, String request, + String requestUri, String originHeaders) { redirectUriResponse.setBaseRedirectUri(ConfigurationFactory.getConfiguration().getAuthorizationPage()); @@ -615,12 +655,24 @@ private void redirectToAuthorizationPage( if (StringUtils.isNotBlank(acrValuesStr)) { redirectUriResponse.addResponseParameter(AuthorizeRequestParam.ACR_VALUES, acrValuesStr); } + if ((amrValues != null) && !amrValues.isEmpty()) { + String amrValuesStr = toJSONArray(amrValues).toString(); + redirectUriResponse.addResponseParameter(AuthorizeRequestParam.AMR_VALUES, amrValuesStr); + } if (StringUtils.isNotBlank(request)) { redirectUriResponse.addResponseParameter(AuthorizeRequestParam.REQUEST, request); } if (StringUtils.isNotBlank(requestUri)) { redirectUriResponse.addResponseParameter(AuthorizeRequestParam.REQUEST_URI, requestUri); } + if (StringUtils.isNotBlank(requestUri)) { + redirectUriResponse.addResponseParameter(AuthorizeRequestParam.REQUEST_URI, requestUri); + } + + // mod_ox param + if (StringUtils.isNotBlank(originHeaders)) { + redirectUriResponse.addResponseParameter(AuthorizeRequestParam.ORIGIN_HEADERS, originHeaders); + } } /** diff --git a/Server/src/main/java/org/xdi/oxauth/clientinfo/ws/rs/ClientInfoRestWebService.java b/Server/src/main/java/org/xdi/oxauth/clientinfo/ws/rs/ClientInfoRestWebService.java index 98e50c18a1..9130590691 100644 --- a/Server/src/main/java/org/xdi/oxauth/clientinfo/ws/rs/ClientInfoRestWebService.java +++ b/Server/src/main/java/org/xdi/oxauth/clientinfo/ws/rs/ClientInfoRestWebService.java @@ -1,5 +1,7 @@ package org.xdi.oxauth.clientinfo.ws.rs; +import com.wordnik.swagger.annotations.Api; + import javax.ws.rs.*; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; @@ -12,6 +14,7 @@ * @author Javier Rojas Blum Date: 07.19.2012 */ @Path("/oxauth") +@Api(value = "/oxauth", description = "The ClientInfo Endpoint is an OAuth 2.0 Protected Resource that returns Claims about the registered client.") public interface ClientInfoRestWebService { @GET diff --git a/Server/src/main/java/org/xdi/oxauth/federation/ws/rs/FederationDataWS.java b/Server/src/main/java/org/xdi/oxauth/federation/ws/rs/FederationDataWS.java index 4a876bc55f..d6dbe8c12d 100644 --- a/Server/src/main/java/org/xdi/oxauth/federation/ws/rs/FederationDataWS.java +++ b/Server/src/main/java/org/xdi/oxauth/federation/ws/rs/FederationDataWS.java @@ -1,5 +1,7 @@ package org.xdi.oxauth.federation.ws.rs; +import com.wordnik.swagger.annotations.Api; + import javax.servlet.http.HttpServletRequest; import javax.ws.rs.FormParam; import javax.ws.rs.POST; @@ -18,6 +20,8 @@ */ @Path("/oxauth") +@Api(value = "/oxauth", description = "Federation Endpoint provides ability to send JOIN (to federation) requests.") + public interface FederationDataWS { @POST @Path("/federation") diff --git a/Server/src/main/java/org/xdi/oxauth/federation/ws/rs/FederationMetadataWS.java b/Server/src/main/java/org/xdi/oxauth/federation/ws/rs/FederationMetadataWS.java index 3910722764..0b6a40511d 100644 --- a/Server/src/main/java/org/xdi/oxauth/federation/ws/rs/FederationMetadataWS.java +++ b/Server/src/main/java/org/xdi/oxauth/federation/ws/rs/FederationMetadataWS.java @@ -1,5 +1,7 @@ package org.xdi.oxauth.federation.ws.rs; +import com.wordnik.swagger.annotations.Api; + import javax.servlet.http.HttpServletRequest; import javax.ws.rs.GET; import javax.ws.rs.Path; @@ -18,6 +20,7 @@ * @version 0.9, 11/09/2012 */ @Path("/oxauth") +@Api(value="/oxauth", description = "Federation Metadata Endpoint provided metadata information about federation.") public interface FederationMetadataWS { @GET diff --git a/Server/src/main/java/org/xdi/oxauth/idgen/ws/rs/IdGenRestWebService.java b/Server/src/main/java/org/xdi/oxauth/idgen/ws/rs/IdGenRestWebService.java index 0d63a5b361..b45fcc7a92 100644 --- a/Server/src/main/java/org/xdi/oxauth/idgen/ws/rs/IdGenRestWebService.java +++ b/Server/src/main/java/org/xdi/oxauth/idgen/ws/rs/IdGenRestWebService.java @@ -1,5 +1,8 @@ package org.xdi.oxauth.idgen.ws.rs; +import com.wordnik.swagger.annotations.Api; +import com.wordnik.swagger.annotations.ApiOperation; +import com.wordnik.swagger.annotations.ApiParam; import org.apache.commons.lang.StringUtils; import org.jboss.seam.annotations.In; import org.jboss.seam.annotations.Logger; @@ -36,6 +39,7 @@ @Name("idGenWS") @Path("/id") +@Api(value = "/id", description = "ID Generation") public class IdGenRestWebService { private static class UnauthorizedResponseHolder { @@ -64,13 +68,30 @@ public static Response unauthorizedResponse() { @GET @Path("/{prefix}/{type}/") @Produces(MediaType.APPLICATION_JSON) - public Response generateJsonInum(@PathParam("prefix") String prefix, @PathParam("type") String type, @HeaderParam("Authorization") String p_authorization) { + @ApiOperation( + value = "Generates ID for given prefix and type.", + notes = "Generates ID for given prefix and type. ", + response = Response.class, + responseContainer = "String" + ) + public Response generateJsonInum( + @PathParam("prefix") @ApiParam(value="Prefix for id. E.g. if prefix is @!1111 and server will generate id: !0000 then ID returned by service would be: @!1111!0000", required = true) + String prefix, + @PathParam("type") @ApiParam(value="Type of id", required = true, allowableValues = "PEOPLE, ORGANIZATION, APPLIANCE, GROUP, SERVER, ATTRIBUTE, TRUST_RELATIONSHIP, CLIENTS") + String type, + @HeaderParam("Authorization") String p_authorization) { return generateId(prefix, type, p_authorization, MediaType.APPLICATION_JSON); } @GET @Path("/{prefix}/{type}/") @Produces(MediaType.TEXT_PLAIN) + @ApiOperation( + value = "Generates ID for given prefix and type.", + notes = "Generates ID for given prefix and type. ", + response = Response.class, + responseContainer = "String" + ) public Response generateTextInum(@PathParam("prefix") String prefix, @PathParam("type") String type, @HeaderParam("Authorization") String p_authorization) { return generateId(prefix, type, p_authorization, MediaType.TEXT_PLAIN); } @@ -78,14 +99,36 @@ public Response generateTextInum(@PathParam("prefix") String prefix, @PathParam( @GET @Path("/{prefix}/{type}/") @Produces(MediaType.TEXT_XML) - public Response generateXmlInum(@PathParam("prefix") String prefix, @PathParam("type") String type, @HeaderParam("Authorization") String p_authorization) { + @ApiOperation( + value = "Generates ID for given prefix and type.", + notes = "Generates ID for given prefix and type. ", + response = Response.class, + responseContainer = "String" + ) + public Response generateXmlInum( + @PathParam("prefix") @ApiParam(value="Prefix for id. E.g. if prefix is @!1111 and server will generate id: !0000 then ID returned by service would be: @!1111!0000", required = true) + String prefix, + @PathParam("type") @ApiParam(value="Type of id", required = true, allowableValues = "PEOPLE, ORGANIZATION, APPLIANCE, GROUP, SERVER, ATTRIBUTE, TRUST_RELATIONSHIP, CLIENTS") + String type, + @HeaderParam("Authorization") String p_authorization) { return generateId(prefix, type, p_authorization, MediaType.TEXT_XML); } @GET @Path("/{prefix}/{type}/") @Produces(MediaType.TEXT_HTML) - public Response generateHtmlInum(@PathParam("prefix") String prefix, @PathParam("type") String type, @HeaderParam("Authorization") String p_authorization) { + @ApiOperation( + value = "Generates ID for given prefix and type.", + notes = "Generates ID for given prefix and type. ", + response = Response.class, + responseContainer = "String" + ) + public Response generateHtmlInum( + @PathParam("prefix") @ApiParam(value="Prefix for id. E.g. if prefix is @!1111 and server will generate id: !0000 then ID returned by service would be: @!1111!0000", required = true) + String prefix, + @PathParam("type") @ApiParam(value="Type of id", required = true, allowableValues = "PEOPLE, ORGANIZATION, APPLIANCE, GROUP, SERVER, ATTRIBUTE, TRUST_RELATIONSHIP, CLIENTS") + String type, + @HeaderParam("Authorization") String p_authorization) { return generateId(prefix, type, p_authorization, MediaType.TEXT_HTML); } diff --git a/Server/src/main/java/org/xdi/oxauth/introspection/ws/rs/IntrospectionWebService.java b/Server/src/main/java/org/xdi/oxauth/introspection/ws/rs/IntrospectionWebService.java index ff782a07bc..e880e82a8e 100644 --- a/Server/src/main/java/org/xdi/oxauth/introspection/ws/rs/IntrospectionWebService.java +++ b/Server/src/main/java/org/xdi/oxauth/introspection/ws/rs/IntrospectionWebService.java @@ -1,5 +1,6 @@ package org.xdi.oxauth.introspection.ws.rs; +import com.wordnik.swagger.annotations.Api; import org.apache.commons.lang.StringUtils; import org.jboss.seam.annotations.In; import org.jboss.seam.annotations.Logger; @@ -30,6 +31,10 @@ */ @Name("introspectionWS") @Path("/introspection") +@Api(value= "/introspection", description = "The Introspection Endpoint is an OAuth 2 Endpoint that responds to " + + " HTTP GET and HTTP POST requests from token holders. The endpoint " + + " takes a single parameter representing the token (and optionally " + + " further authentication) and returns a JSON document representing the meta information surrounding the token.") public class IntrospectionWebService { @Logger diff --git a/Server/src/main/java/org/xdi/oxauth/jwk/ws/rs/JwkRestWebService.java b/Server/src/main/java/org/xdi/oxauth/jwk/ws/rs/JwkRestWebService.java index 6cfc6d2bf6..6c460ce315 100644 --- a/Server/src/main/java/org/xdi/oxauth/jwk/ws/rs/JwkRestWebService.java +++ b/Server/src/main/java/org/xdi/oxauth/jwk/ws/rs/JwkRestWebService.java @@ -1,5 +1,7 @@ package org.xdi.oxauth.jwk.ws.rs; +import com.wordnik.swagger.annotations.Api; + import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; @@ -27,6 +29,7 @@ * @author Javier Rojas Blum Date: 11.15.2011 */ @Path("/oxauth") +@Api(value = "/oxauth", description = "JWK Endpoint provides list of JWK used by server. A JSON Web Key (JWK) is a JSON data structure that represents a set of public keys as a JSON object [RFC4627].") public interface JwkRestWebService { /** diff --git a/Server/src/main/java/org/xdi/oxauth/model/authorize/JwtAuthorizationRequest.java b/Server/src/main/java/org/xdi/oxauth/model/authorize/JwtAuthorizationRequest.java index cd80dd1e1f..4da2877029 100644 --- a/Server/src/main/java/org/xdi/oxauth/model/authorize/JwtAuthorizationRequest.java +++ b/Server/src/main/java/org/xdi/oxauth/model/authorize/JwtAuthorizationRequest.java @@ -311,10 +311,10 @@ private void loadPayload(String payload) throws JSONException, UnsupportedEncodi JSONObject claimsJsonObject = jsonPayload.getJSONObject("claims"); if (claimsJsonObject.has("userinfo")) { - userInfoMember = new UserInfoMember(jsonPayload.getJSONObject("userinfo")); + userInfoMember = new UserInfoMember(claimsJsonObject.getJSONObject("userinfo")); } if (claimsJsonObject.has("id_token")) { - idTokenMember = new IdTokenMember(jsonPayload.getJSONObject("id_token")); + idTokenMember = new IdTokenMember(claimsJsonObject.getJSONObject("id_token")); } } } diff --git a/Server/src/main/java/org/xdi/oxauth/model/common/AuthorizationGrant.java b/Server/src/main/java/org/xdi/oxauth/model/common/AuthorizationGrant.java index c632e9a147..57af48f91a 100644 --- a/Server/src/main/java/org/xdi/oxauth/model/common/AuthorizationGrant.java +++ b/Server/src/main/java/org/xdi/oxauth/model/common/AuthorizationGrant.java @@ -119,15 +119,8 @@ public RefreshToken createRefreshToken() { */ @Override public IdToken createIdToken(String nonce, AuthorizationCode authorizationCode, AccessToken accessToken, - Map claims) throws SignatureException, StringEncrypter.EncryptionException, InvalidJwtException, InvalidJweException { - IdToken idToken = grant.createIdToken(nonce, authorizationCode, accessToken, claims); - - idToken.setAuthLevel(getAuthLevel()); - idToken.setAuthMode(getAuthMode()); - - grant.save(); // call save after object modification!!! - - return idToken; + Map claims, String authLevel, String authMode) throws SignatureException, StringEncrypter.EncryptionException, InvalidJwtException, InvalidJweException { + return grant.createIdToken(nonce, authorizationCode, accessToken, claims, authLevel, authMode); } /** @@ -368,6 +361,9 @@ public void setAuthMode(String authMode) { grant.setAuthMode(authMode); } + /** + * Saves changes asynchronously + */ @Override public void save() { grant.save(); diff --git a/Server/src/main/java/org/xdi/oxauth/model/common/AuthorizationGrantInMemory.java b/Server/src/main/java/org/xdi/oxauth/model/common/AuthorizationGrantInMemory.java index b8475c8089..40fd33c739 100644 --- a/Server/src/main/java/org/xdi/oxauth/model/common/AuthorizationGrantInMemory.java +++ b/Server/src/main/java/org/xdi/oxauth/model/common/AuthorizationGrantInMemory.java @@ -1,6 +1,5 @@ package org.xdi.oxauth.model.common; -import org.apache.log4j.Logger; import org.xdi.oxauth.model.exception.InvalidJweException; import org.xdi.oxauth.model.exception.InvalidJwtException; import org.xdi.oxauth.model.jwe.Jwe; @@ -24,7 +23,7 @@ public class AuthorizationGrantInMemory extends AbstractAuthorizationGrant { - private static final Logger LOGGER = Logger.getLogger(AuthorizationGrantInMemory.class); +// private static final Logger LOGGER = Logger.getLogger(AuthorizationGrantInMemory.class); private TokenIssuerObserver tokenIssuerObserver; private AuthorizationGrant parentRef; @@ -114,7 +113,7 @@ public RefreshToken createRefreshToken() { */ @Override public IdToken createIdToken(String nonce, AuthorizationCode authorizationCode, AccessToken accessToken, - Map claims) throws SignatureException, StringEncrypter.EncryptionException, InvalidJwtException, InvalidJweException { + Map claims, String authLevel, String authMode) throws SignatureException, StringEncrypter.EncryptionException, InvalidJwtException, InvalidJweException { if (getIdToken() == null) { IdToken idToken = createIdToken(this, nonce, authorizationCode, accessToken, claims); setIdToken(idToken); diff --git a/Server/src/main/java/org/xdi/oxauth/model/common/AuthorizationGrantLdap.java b/Server/src/main/java/org/xdi/oxauth/model/common/AuthorizationGrantLdap.java index 6ab16bd7d3..99acb0ffcf 100644 --- a/Server/src/main/java/org/xdi/oxauth/model/common/AuthorizationGrantLdap.java +++ b/Server/src/main/java/org/xdi/oxauth/model/common/AuthorizationGrantLdap.java @@ -15,6 +15,9 @@ import java.util.Date; import java.util.List; import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; /** * @author Yuriy Zabrovarnyy @@ -26,6 +29,16 @@ public class AuthorizationGrantLdap extends AbstractAuthorizationGrant { private static final Logger LOGGER = Logger.getLogger(AuthorizationGrantLdap.class); + private static final int THREADS_COUNT = 200; + + private final ExecutorService executorService = Executors.newFixedThreadPool(THREADS_COUNT, new ThreadFactory() { + public Thread newThread(Runnable p_r) { + Thread thread = new Thread(p_r); + thread.setDaemon(true); + return thread; + } + }); + private final GrantService m_grantService = GrantService.instance(); public AuthorizationGrantLdap(User user, AuthorizationGrantType authorizationGrantType, Client client, @@ -37,18 +50,20 @@ public AuthorizationGrantLdap(User user, AuthorizationGrantType authorizationGra public String checkScopesPolicy(String scope) { final String result = super.checkScopesPolicy(scope); save(); - // yuriyz: Check, maybe store scopes in asynchronous call to release thread faster -// Executors.newSingleThreadExecutor().execute(new Runnable() { -// @Override -// public void run() { -// save(); -// } -// }); return result; } @Override public void save() { + executorService.execute(new Runnable() { + @Override + public void run() { + saveImpl(); + } + }); + } + + private void saveImpl() { String grantId = getGrantId(); if (grantId != null && StringUtils.isNotBlank(grantId)) { final List grants = m_grantService.getGrantsByGrantId(grantId); @@ -114,12 +129,20 @@ public RefreshToken createRefreshToken() { @Override public IdToken createIdToken(String nonce, AuthorizationCode authorizationCode, AccessToken accessToken, - Map claims) throws SignatureException, StringEncrypter.EncryptionException, InvalidJwtException, InvalidJweException { + Map claims, String authLevel, String authMode) throws SignatureException, StringEncrypter.EncryptionException, InvalidJwtException, InvalidJweException { try { final IdToken idToken = AuthorizationGrantInMemory.createIdToken(this, nonce, authorizationCode, accessToken, claims); if (idToken.getExpiresIn() > 0) { - persist(asToken(idToken)); + final TokenLdap tokenLdap = asToken(idToken); + tokenLdap.setAuthLevel(authLevel); + tokenLdap.setAuthMode(authMode); + persist(tokenLdap); } + + // is it really neccessary to propagate to all tokens? + setAuthLevel(authLevel); + setAuthMode(authMode); + save(); // asynchronous save return idToken; } catch (Exception e) { LOGGER.trace(e.getMessage(), e); diff --git a/Server/src/main/java/org/xdi/oxauth/model/common/IAuthorizationGrant.java b/Server/src/main/java/org/xdi/oxauth/model/common/IAuthorizationGrant.java index 1c55851006..d249de8880 100644 --- a/Server/src/main/java/org/xdi/oxauth/model/common/IAuthorizationGrant.java +++ b/Server/src/main/java/org/xdi/oxauth/model/common/IAuthorizationGrant.java @@ -37,7 +37,8 @@ public interface IAuthorizationGrant { public RefreshToken createRefreshToken(); public IdToken createIdToken(String nonce, AuthorizationCode authorizationCode, AccessToken accessToken, - Map claims) throws SignatureException, StringEncrypter.EncryptionException, InvalidJwtException, InvalidJweException; + Map claims, String authLevel, String authMode) + throws SignatureException, StringEncrypter.EncryptionException, InvalidJwtException, InvalidJweException; public RefreshToken getRefreshToken(String refreshTokenCode); @@ -107,5 +108,8 @@ public IdToken createIdToken(String nonce, AuthorizationCode authorizationCode, public void setAuthMode(String authMode); + /** + * Saves changes asynchronously + */ public void save(); } \ No newline at end of file diff --git a/Server/src/main/java/org/xdi/oxauth/model/common/SessionId.java b/Server/src/main/java/org/xdi/oxauth/model/common/SessionId.java index 3453cfad7f..2d76062a7d 100644 --- a/Server/src/main/java/org/xdi/oxauth/model/common/SessionId.java +++ b/Server/src/main/java/org/xdi/oxauth/model/common/SessionId.java @@ -1,5 +1,8 @@ package org.xdi.oxauth.model.common; +import java.io.Serializable; +import java.util.Date; + import org.gluu.site.ldap.persistence.annotation.LdapAttribute; import org.gluu.site.ldap.persistence.annotation.LdapDN; import org.gluu.site.ldap.persistence.annotation.LdapEntry; @@ -8,9 +11,6 @@ import org.jboss.seam.annotations.AutoCreate; import org.jboss.seam.annotations.Name; -import java.io.Serializable; -import java.util.Date; - /** * @author Yuriy Zabrovarnyy * @author Javier Rojas Blum @@ -24,19 +24,29 @@ public class SessionId implements Serializable { @LdapDN private String dn; + @LdapAttribute(name = "uniqueIdentifier") private String id; + @LdapAttribute(name = "lastModifiedTime") private Date lastUsedAt; + @LdapAttribute(name = "oxAuthUserDN") private String userDn; + @LdapAttribute(name = "oxAuthAuthenticationTime") private Date authenticationTime; + @LdapAttribute(name = "oxAuthPermissionGranted") private Boolean permissionGranted; + @LdapJsonObject @LdapAttribute(name = "oxAuthPermissionGrantedMap") private SessionIdAccessMap permissionGrantedMap; + + @LdapJsonObject + @LdapAttribute(name = "oxAuthSessionAttribute") + private SessionIdAttribute[] sessionIdAttributes; public SessionId() { } @@ -111,7 +121,15 @@ public void addPermission(String clientId, Boolean granted) { permissionGrantedMap.put(clientId, granted); } - @Override + public SessionIdAttribute[] getSessionIdAttributes() { + return sessionIdAttributes; + } + + public void setSessionIdAttributes(SessionIdAttribute[] sessionIdAttributes) { + this.sessionIdAttributes = sessionIdAttributes; + } + + @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; diff --git a/Server/src/main/java/org/xdi/oxauth/model/common/SessionIdAttribute.java b/Server/src/main/java/org/xdi/oxauth/model/common/SessionIdAttribute.java new file mode 100644 index 0000000000..9c8ccf3257 --- /dev/null +++ b/Server/src/main/java/org/xdi/oxauth/model/common/SessionIdAttribute.java @@ -0,0 +1,36 @@ +package org.xdi.oxauth.model.common; + +import java.io.Serializable; + +import org.codehaus.jackson.annotate.JsonPropertyOrder; + +/** + * @author Yuriy Movchan + * @version 0.1, 07/31/2014 + */ + +@JsonPropertyOrder({ "name", "value" }) +public class SessionIdAttribute implements Serializable { + + private static final long serialVersionUID = -4302759878934177750L; + + private String name; + private String value; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + +} diff --git a/Server/src/main/java/org/xdi/oxauth/model/common/UnmodifiableAuthorizationGrant.java b/Server/src/main/java/org/xdi/oxauth/model/common/UnmodifiableAuthorizationGrant.java index cfe8a6e85a..10547f5c97 100644 --- a/Server/src/main/java/org/xdi/oxauth/model/common/UnmodifiableAuthorizationGrant.java +++ b/Server/src/main/java/org/xdi/oxauth/model/common/UnmodifiableAuthorizationGrant.java @@ -73,7 +73,7 @@ public RefreshToken createRefreshToken() { @Override public IdToken createIdToken(String nonce, AuthorizationCode authorizationCode, AccessToken accessToken, - Map claims) throws SignatureException, StringEncrypter.EncryptionException, InvalidJwtException, InvalidJweException { + Map claims, String authMode, String authLevel) throws SignatureException, StringEncrypter.EncryptionException, InvalidJwtException, InvalidJweException { throw new UnsupportedOperationException("Not allowed for UnmodifiableAuthorizationGrant."); } diff --git a/Server/src/main/java/org/xdi/oxauth/register/ws/rs/RegisterRestWebService.java b/Server/src/main/java/org/xdi/oxauth/register/ws/rs/RegisterRestWebService.java index cd31383380..edf8476019 100644 --- a/Server/src/main/java/org/xdi/oxauth/register/ws/rs/RegisterRestWebService.java +++ b/Server/src/main/java/org/xdi/oxauth/register/ws/rs/RegisterRestWebService.java @@ -1,5 +1,7 @@ package org.xdi.oxauth.register.ws.rs; +import com.wordnik.swagger.annotations.Api; + import javax.servlet.http.HttpServletRequest; import javax.ws.rs.GET; import javax.ws.rs.HeaderParam; @@ -21,6 +23,7 @@ * @version 0.1, 01.11.2012 */ @Path("/oxauth") +@Api(value = "/oxauth", description = "The Client Registration Endpoint is an OAuth 2.0 Protected Resource through which a new Client registration can be requested. The OpenID Provider MAY require an Initial Access Token that is provisioned out-of-band (in a manner that is out of scope for this specification) to restrict registration requests to only authorized Clients or developers.") public interface RegisterRestWebService { /** diff --git a/Server/src/main/java/org/xdi/oxauth/service/AuthenticationService.java b/Server/src/main/java/org/xdi/oxauth/service/AuthenticationService.java index eb036eb235..72c9c776ab 100644 --- a/Server/src/main/java/org/xdi/oxauth/service/AuthenticationService.java +++ b/Server/src/main/java/org/xdi/oxauth/service/AuthenticationService.java @@ -1,9 +1,23 @@ package org.xdi.oxauth.service; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import javax.faces.context.FacesContext; +import javax.servlet.http.HttpServletRequest; + import org.apache.commons.lang.StringUtils; import org.gluu.site.ldap.persistence.LdapEntryManager; import org.gluu.site.ldap.persistence.exception.EntryPersistenceException; -import org.hibernate.annotations.common.util.StringHelper; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.AutoCreate; import org.jboss.seam.annotations.In; @@ -19,20 +33,17 @@ import org.xdi.model.SimpleProperty; import org.xdi.model.ldap.GluuLdapConfiguration; import org.xdi.oxauth.authorize.ws.rs.AuthorizeAction; +import org.xdi.oxauth.model.authorize.AuthorizeRequestParam; import org.xdi.oxauth.model.common.CustomAttribute; import org.xdi.oxauth.model.common.Prompt; import org.xdi.oxauth.model.common.SessionId; +import org.xdi.oxauth.model.common.SessionIdAttribute; import org.xdi.oxauth.model.common.SimpleUser; import org.xdi.oxauth.model.common.User; import org.xdi.oxauth.model.session.OAuthCredentials; import org.xdi.oxauth.model.util.Util; import org.xdi.oxauth.util.ServerUtil; - -import javax.faces.context.FacesContext; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.util.*; -import java.util.Map.Entry; +import org.xdi.util.StringHelper; /** * Authentication service methods @@ -45,6 +56,7 @@ public class AuthenticationService { private static final String STORED_REQUEST_PARAMETERS = "stored_request_parameters"; + private static final String STORED_ORIGIN_HEADERS = "stored_origin_headers"; @Logger private Log log; @@ -338,6 +350,32 @@ public Map restoreRequestParametersFromSession() { return null; } + public void storeRequestHeadersInSession(HttpServletRequest request) { + String originHeaders = request.getParameter(AuthorizeRequestParam.ORIGIN_HEADERS); + if (StringHelper.isEmpty(originHeaders)) { + return; + } + + log.debug("Storing origin_headers: '{0}'", originHeaders); + Context sessionContext = Contexts.getSessionContext(); + sessionContext.set(STORED_ORIGIN_HEADERS, originHeaders); + +// SessionIdAttribute sessionIdAttribute = new SessionIdAttribute(); +// sessionIdAttribute.setName(STORED_ORIGIN_HEADERS); +// sessionIdAttribute.setValue(originHeaders); +// sessionIdService.addSessionAttribute(sessionIdService.getSessionIdFromCookies(request), sessionIdAttribute); + } + + public String getRequestHeadersFromSession() { + Context sessionContext = Contexts.getSessionContext(); + + if (sessionContext.isSet(STORED_ORIGIN_HEADERS)) { + return (String) sessionContext.get(STORED_ORIGIN_HEADERS); + } + + return null; + } + public static AuthenticationService instance() { return ServerUtil.instance(AuthenticationService.class); } diff --git a/Server/src/main/java/org/xdi/oxauth/service/ExternalAuthenticationService.java b/Server/src/main/java/org/xdi/oxauth/service/ExternalAuthenticationService.java index 1aa638b8f9..c68966b4b4 100644 --- a/Server/src/main/java/org/xdi/oxauth/service/ExternalAuthenticationService.java +++ b/Server/src/main/java/org/xdi/oxauth/service/ExternalAuthenticationService.java @@ -14,6 +14,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import org.apache.commons.io.IOUtils; +import org.jboss.seam.Component; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.AutoCreate; import org.jboss.seam.annotations.In; @@ -53,6 +54,8 @@ public class ExternalAuthenticationService implements Serializable { private static final long serialVersionUID = -1225880597520443390L; + public final static String AMR_METHOD_PREFIX = "https://schema.gluu.org/openid/amr/method/"; + private final static String EVENT_TYPE = "ExternalAuthenticationTimerEvent"; private final static int DEFAULT_INTERVAL = 30; // 30 seconds @@ -62,9 +65,9 @@ public class ExternalAuthenticationService implements Serializable { // private transient ExternalAuthenticatorConfiguration defaultExternalAuthenticator; - private transient Map externalAuthenticatorConfigurations; - private transient Map> externalAuthenticatorConfigurationsByUsageType; - private transient Map defaultExternalAuthenticators; + private Map externalAuthenticatorConfigurations; + private Map> externalAuthenticatorConfigurationsByUsageType; + private Map defaultExternalAuthenticators; @Logger private Log log; @@ -471,6 +474,36 @@ public ExternalAuthenticatorConfiguration determineExternalAuthenticatorConfigur return externalAuthenticatorConfiguration; } + public ExternalAuthenticatorConfiguration determineExternalAuthenticatorConfiguration(AuthenticationScriptUsageType usageType, List amrValues) { + List authModes = getAuthModesByAmrValues(amrValues); + if (authModes.size() > 0) { + for (String authMode : authModes) { + for (ExternalAuthenticatorConfiguration externalAuthenticatorConfiguration : this.externalAuthenticatorConfigurationsByUsageType.get(usageType)) { + if (StringHelper.equalsIgnoreCase(authMode, externalAuthenticatorConfiguration.getName())) { + return externalAuthenticatorConfiguration; + } + } + } + } + + return null; + } + + private List getAuthModesByAmrValues(List amrValues) { + List authModes = new ArrayList(); + + for (String amrValue : amrValues) { + if (StringHelper.isNotEmpty(amrValue) && StringHelper.toLowerCase(amrValue).startsWith(AMR_METHOD_PREFIX)) { + String authMode = amrValue.substring(AMR_METHOD_PREFIX.length()); + if (externalAuthenticatorConfigurations.containsKey(StringHelper.toLowerCase(authMode))) { + authModes.add(authMode); + } + } + } + + return authModes; + } + public ExternalAuthenticatorConfiguration determineExternalAuthenticatorForWorkflow(AuthenticationScriptUsageType usageType, ExternalAuthenticatorConfiguration externalAuthenticatorConfiguration) { // Validate API version int apiVersion = executeExternalAuthenticatorGetApiVersion(externalAuthenticatorConfiguration); @@ -516,15 +549,30 @@ public ExternalAuthenticatorConfiguration getExternalAuthenticatorConfiguration( } public ExternalAuthenticatorConfiguration getExternalAuthenticatorConfiguration(String name) { - for (ExternalAuthenticatorConfiguration externalAuthenticatorConfiguration : this.externalAuthenticatorConfigurations.values()) { - if (StringHelper.equalsIgnoreCase(name, externalAuthenticatorConfiguration.getName())) { - return externalAuthenticatorConfiguration; + for (Entry externalAuthenticatorConfigurationEntry : this.externalAuthenticatorConfigurations.entrySet()) { + if (StringHelper.equalsIgnoreCase(name, externalAuthenticatorConfigurationEntry.getKey())) { + return externalAuthenticatorConfigurationEntry.getValue(); } } return null; } + public List getExternalAuthenticatorConfigurations() { + return new ArrayList(this.externalAuthenticatorConfigurations.values()); + } + + public List getAmrValuesList() { + List amrValues = new ArrayList(); + + for (Entry externalAuthenticatorConfigurationEntry : this.externalAuthenticatorConfigurations.entrySet()) { + String amrValue = AMR_METHOD_PREFIX + externalAuthenticatorConfigurationEntry.getKey(); + amrValues.add(amrValue); + } + + return amrValues; + } + private boolean isValidateUsageType(AuthenticationScriptUsageType usageType, ExternalAuthenticatorConfiguration externalAuthenticatorConfiguration) { if (externalAuthenticatorConfiguration == null) { return false; @@ -556,4 +604,8 @@ private boolean isValidateUsageType(AuthenticationScriptUsageType usageType, Ext return false; } + public static ExternalAuthenticationService instance() { + return (ExternalAuthenticationService) Component.getInstance(ExternalAuthenticationService.class); + } + } diff --git a/Server/src/main/java/org/xdi/oxauth/service/SessionIdService.java b/Server/src/main/java/org/xdi/oxauth/service/SessionIdService.java index 2485b81c63..6960b4b548 100644 --- a/Server/src/main/java/org/xdi/oxauth/service/SessionIdService.java +++ b/Server/src/main/java/org/xdi/oxauth/service/SessionIdService.java @@ -1,8 +1,17 @@ package org.xdi.oxauth.service; -import com.unboundid.ldap.sdk.Filter; -import com.unboundid.ldap.sdk.LDAPException; -import com.unboundid.util.StaticUtils; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import javax.faces.context.FacesContext; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + import org.gluu.site.ldap.persistence.LdapEntryManager; import org.jboss.seam.Component; import org.jboss.seam.ScopeType; @@ -16,23 +25,18 @@ import org.jboss.seam.log.Log; import org.xdi.oxauth.model.common.Prompt; import org.xdi.oxauth.model.common.SessionId; +import org.xdi.oxauth.model.common.SessionIdAttribute; import org.xdi.oxauth.model.config.ConfigurationFactory; import org.xdi.oxauth.model.util.Util; +import org.xdi.util.ArrayHelper; import org.xdi.util.StringHelper; -import javax.faces.context.FacesContext; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Date; -import java.util.List; -import java.util.UUID; -import java.util.concurrent.TimeUnit; +import com.unboundid.ldap.sdk.Filter; +import com.unboundid.util.StaticUtils; /** * @author Yuriy Zabrovarnyy + * @author Yuriy Movchan * @version 0.9, 20/12/2012 */ @@ -73,6 +77,33 @@ public String getSessionIdFromCookie(HttpServletRequest request) { return ""; } + public String getSessionIdFromOpbsCookie(HttpServletRequest request) { + try { + final Cookie[] cookies = request.getCookies(); + if (cookies != null) { + for (Cookie cookie : cookies) { + if (cookie.getName().equals("opbs") /*&& cookie.getSecure()*/) { + log.trace("Found session_id cookie: {0}", cookie.getValue()); + return cookie.getValue(); + } + } + } + } catch (Exception e) { + log.error(e.getMessage(), e); + } + return ""; + } + + public String getSessionIdFromCookies(HttpServletRequest request) { + String sessionId = getSessionIdFromOpbsCookie(request); + + if (StringHelper.isEmpty(sessionId)) { + sessionId = getSessionIdFromCookie(request); + } + + return sessionId; + } + public void createSessionIdCookie(String sessionId) { try { final Object response = FacesContext.getCurrentInstance().getExternalContext().getResponse(); @@ -196,18 +227,15 @@ public SessionId getSessionId(String sessionId) { } try { + final SessionId entity = getSessionByDN(dn(sessionId)); log.trace("Try to get session by id: {0} ...", sessionId); - final List entries = ldapEntryManager.findEntries(getBaseDn(), SessionId.class, Filter.create(String.format("uniqueIdentifier=%s", sessionId))); - if (entries != null && !entries.isEmpty()) { - final SessionId entity = entries.get(0); + if (entity != null) { log.trace("Session dn: {0}", entity.getDn()); if (isSessionValid(entity)) { return entity; } } - } catch (LDAPException e) { - log.error(e.getMessage(), e); } catch (Exception e) { log.error(e.getMessage(), e); } @@ -236,17 +264,14 @@ public void updateSessionWithLastUsedDate(SessionId p_sessionId) { } public void updateSessionWithLastUsedDate(SessionId p_sessionId, List prompts) { - try { if (!isPersisted(prompts)) { return; } final Date newDate = new Date(); - p_sessionId.setLastUsedAt(newDate); - ldapEntryManager.merge(p_sessionId); - } catch (Exception e) { - log.error(e.getMessage(), e); - } + p_sessionId.setLastUsedAt(newDate); + + updateSession(p_sessionId); } public void cleanUpSessions() { @@ -286,4 +311,36 @@ public boolean isSessionValid(SessionId sessionId) { return true; } + public boolean updateSession(SessionId p_sessionId) { + try { + ldapEntryManager.merge(p_sessionId); + } catch (Exception e) { + log.error(e.getMessage(), e); + + return false; + } + + return true; + } + + public void addSessionAttribute(String sessionId, SessionIdAttribute sessionIdAttribute) { + if (StringHelper.isEmpty(sessionId)) { + return; + } + + SessionId entity = getSessionId(sessionId); + + SessionIdAttribute[] sessionIdAttributes = entity.getSessionIdAttributes(); + SessionIdAttribute[] newSessionIdAttributes; + if (ArrayHelper.isEmpty(sessionIdAttributes)) { + newSessionIdAttributes = new SessionIdAttribute[] {sessionIdAttribute}; + } else { + newSessionIdAttributes = ArrayHelper.arrayMerge(sessionIdAttributes, new SessionIdAttribute[] { sessionIdAttribute }); + } + + entity.setSessionIdAttributes(newSessionIdAttributes); + + updateSession(entity); + } + } diff --git a/Server/src/main/java/org/xdi/oxauth/servlet/OpenIdConfiguration.java b/Server/src/main/java/org/xdi/oxauth/servlet/OpenIdConfiguration.java index a36b93a002..12d53f0116 100644 --- a/Server/src/main/java/org/xdi/oxauth/servlet/OpenIdConfiguration.java +++ b/Server/src/main/java/org/xdi/oxauth/servlet/OpenIdConfiguration.java @@ -49,6 +49,7 @@ import java.io.IOException; import java.io.PrintWriter; +import java.util.ArrayList; import java.util.List; import javax.servlet.ServletException; @@ -66,6 +67,7 @@ import org.xdi.oxauth.model.common.Scope; import org.xdi.oxauth.model.config.ConfigurationFactory; import org.xdi.oxauth.service.AttributeService; +import org.xdi.oxauth.service.ExternalAuthenticationService; import org.xdi.oxauth.service.ScopeService; /** @@ -140,8 +142,9 @@ protected void processRequest(HttpServletRequest request, HttpServletResponse re jsonObj.put(ACR_VALUES_SUPPORTED, acrValuesSupported); } + ExternalAuthenticationService externalAuthenticationService = ExternalAuthenticationService.instance(); JSONArray amrValuesSupported = new JSONArray(); - for (String amr : ConfigurationFactory.getConfiguration().getAmrValuesSupported()) { + for (String amr : externalAuthenticationService.getAmrValuesList() /*ConfigurationFactory.getConfiguration().getAmrValuesSupported() */) { amrValuesSupported.put(amr); } if (amrValuesSupported.length() > 0) { diff --git a/Server/src/main/java/org/xdi/oxauth/session/ws/rs/EndSessionRestWebService.java b/Server/src/main/java/org/xdi/oxauth/session/ws/rs/EndSessionRestWebService.java index 819f4f0cbd..adbefba418 100644 --- a/Server/src/main/java/org/xdi/oxauth/session/ws/rs/EndSessionRestWebService.java +++ b/Server/src/main/java/org/xdi/oxauth/session/ws/rs/EndSessionRestWebService.java @@ -1,5 +1,6 @@ package org.xdi.oxauth.session.ws.rs; +import com.wordnik.swagger.annotations.Api; import org.xdi.oxauth.model.session.EndSessionRequestParam; import javax.servlet.http.HttpServletRequest; @@ -17,6 +18,7 @@ * @author Javier Rojas Date: 12.15.2011 */ @Path("/oxauth") +@Api(value = "/oxauth", description = "End Session Endpoint - URL at the OP to which an RP can perform a redirect to request that the End-User be logged out at the OP") public interface EndSessionRestWebService { @GET diff --git a/Server/src/main/java/org/xdi/oxauth/token/ws/rs/TokenRestWebService.java b/Server/src/main/java/org/xdi/oxauth/token/ws/rs/TokenRestWebService.java index a8a1355884..0f51377a8e 100644 --- a/Server/src/main/java/org/xdi/oxauth/token/ws/rs/TokenRestWebService.java +++ b/Server/src/main/java/org/xdi/oxauth/token/ws/rs/TokenRestWebService.java @@ -1,5 +1,7 @@ package org.xdi.oxauth.token.ws.rs; +import com.wordnik.swagger.annotations.Api; + import javax.servlet.http.HttpServletRequest; import javax.ws.rs.FormParam; import javax.ws.rs.POST; @@ -16,6 +18,7 @@ * @author Javier Rojas Blum Date: 09.21.2011 */ @Path("/oxauth") +@Api(value = "/oxauth", description = "Token Endpoint is used to obtain an Access Token, an ID Token, and optionally a Refresh Token. The RP (Client) sends a Token Request to the Token Endpoint to obtain a Token Response") public interface TokenRestWebService { @POST diff --git a/Server/src/main/java/org/xdi/oxauth/token/ws/rs/TokenRestWebServiceImpl.java b/Server/src/main/java/org/xdi/oxauth/token/ws/rs/TokenRestWebServiceImpl.java index 939a90fc9c..02bdecade7 100644 --- a/Server/src/main/java/org/xdi/oxauth/token/ws/rs/TokenRestWebServiceImpl.java +++ b/Server/src/main/java/org/xdi/oxauth/token/ws/rs/TokenRestWebServiceImpl.java @@ -117,7 +117,7 @@ public Response requestAccessToken(String grantType, String code, IdToken idToken = null; if (authorizationCodeGrant.getScopes().contains("openid")) { String nonce = authorizationCodeGrant.getNonce(); - idToken = authorizationCodeGrant.createIdToken(nonce, null, accToken, null); + idToken = authorizationCodeGrant.createIdToken(nonce, null, accToken, null, authorizationCodeGrant.getAuthLevel(), authorizationCodeGrant.getAuthMode()); } builder.entity(getJSonResponse(accToken, @@ -155,7 +155,7 @@ public Response requestAccessToken(String grantType, String code, IdToken idToken = null; if (authorizationGrant.getScopes().contains("openid")) { - idToken = authorizationGrant.createIdToken(null, null, null, null); + idToken = authorizationGrant.createIdToken(null, null, null, null, authorizationGrant.getAuthLevel(), authorizationGrant.getAuthMode()); } builder.entity(getJSonResponse(accToken, @@ -178,7 +178,7 @@ public Response requestAccessToken(String grantType, String code, IdToken idToken = null; if (clientCredentialsGrant.getScopes().contains("openid")) { - idToken = clientCredentialsGrant.createIdToken(null, null, null, null); + idToken = clientCredentialsGrant.createIdToken(null, null, null, null, clientCredentialsGrant.getAuthLevel(), clientCredentialsGrant.getAuthMode()); } builder.entity(getJSonResponse(accessToken, @@ -214,7 +214,7 @@ public Response requestAccessToken(String grantType, String code, IdToken idToken = null; if (resourceOwnerPasswordCredentialsGrant.getScopes().contains("openid")) { - idToken = resourceOwnerPasswordCredentialsGrant.createIdToken(null, null, null, null); + idToken = resourceOwnerPasswordCredentialsGrant.createIdToken(null, null, null, null, resourceOwnerPasswordCredentialsGrant.getAuthLevel(), resourceOwnerPasswordCredentialsGrant.getAuthMode()); } builder.entity(getJSonResponse(accessToken, diff --git a/Server/src/main/java/org/xdi/oxauth/uma/ws/rs/MetaDataConfigurationRestWebService.java b/Server/src/main/java/org/xdi/oxauth/uma/ws/rs/MetaDataConfigurationRestWebService.java index b3f60f73c5..3e8cee51b8 100644 --- a/Server/src/main/java/org/xdi/oxauth/uma/ws/rs/MetaDataConfigurationRestWebService.java +++ b/Server/src/main/java/org/xdi/oxauth/uma/ws/rs/MetaDataConfigurationRestWebService.java @@ -1,5 +1,6 @@ package org.xdi.oxauth.uma.ws.rs; +import com.wordnik.swagger.annotations.Api; import org.xdi.oxauth.model.uma.UmaConstants; import javax.ws.rs.GET; @@ -13,6 +14,7 @@ * @author Yuriy Movchan Date: 10/25/2012 */ @Path("/oxauth/uma-configuration") +@Api(value="/oxauth/uma-configuration", description = "The authorization server MUST provide configuration data in a JSON [RFC4627] document that resides in an /uma-configuration directory at its hostmeta [hostmeta] location. The configuration data documents conformance options and endpoints supported by the authorization server. ") public interface MetaDataConfigurationRestWebService { @GET diff --git a/Server/src/main/java/org/xdi/oxauth/uma/ws/rs/ResourceSetPermissionRegistrationRestWebService.java b/Server/src/main/java/org/xdi/oxauth/uma/ws/rs/ResourceSetPermissionRegistrationRestWebService.java index e4552d142e..81e50b2835 100644 --- a/Server/src/main/java/org/xdi/oxauth/uma/ws/rs/ResourceSetPermissionRegistrationRestWebService.java +++ b/Server/src/main/java/org/xdi/oxauth/uma/ws/rs/ResourceSetPermissionRegistrationRestWebService.java @@ -1,5 +1,6 @@ package org.xdi.oxauth.uma.ws.rs; +import com.wordnik.swagger.annotations.Api; import org.xdi.oxauth.model.uma.ResourceSetPermissionRequest; import org.xdi.oxauth.model.uma.UmaConstants; @@ -27,6 +28,9 @@ * @author Yuriy Movchan Date: 10/11/2012 */ @Path("/host/rsrc_pr") +@Api(value="/host/rsrc_pr", description = "The endpoint at which the host registers permissions that it anticipates a " + + " requester will shortly be asking for from the AM. This AM's endpoint is part " + + " of resource set registration API.") public interface ResourceSetPermissionRegistrationRestWebService { @PUT @Path("{host}") diff --git a/Server/src/main/java/org/xdi/oxauth/uma/ws/rs/ResourceSetRegistrationRestWebService.java b/Server/src/main/java/org/xdi/oxauth/uma/ws/rs/ResourceSetRegistrationRestWebService.java index 93b9d10e7d..642997009a 100644 --- a/Server/src/main/java/org/xdi/oxauth/uma/ws/rs/ResourceSetRegistrationRestWebService.java +++ b/Server/src/main/java/org/xdi/oxauth/uma/ws/rs/ResourceSetRegistrationRestWebService.java @@ -1,17 +1,10 @@ package org.xdi.oxauth.uma.ws.rs; +import com.wordnik.swagger.annotations.Api; import org.xdi.oxauth.model.uma.ResourceSet; import org.xdi.oxauth.model.uma.UmaConstants; -import javax.ws.rs.Consumes; -import javax.ws.rs.DELETE; -import javax.ws.rs.GET; -import javax.ws.rs.HeaderParam; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; +import javax.ws.rs.*; import javax.ws.rs.core.Response; import java.util.List; @@ -30,6 +23,7 @@ * Date: 10/03/2012 */ @Path("/host/rsrc/resource_set") +@Api(value="/host/rsrc/resource_set", description = "Resource set registration endpoint to create, read, update, and delete resource set descriptions, along with retrieving lists of such descriptions.") public interface ResourceSetRegistrationRestWebService { @PUT @Path("{rsid}") diff --git a/Server/src/main/java/org/xdi/oxauth/uma/ws/rs/RptPermissionAuthorizationRestWebService.java b/Server/src/main/java/org/xdi/oxauth/uma/ws/rs/RptPermissionAuthorizationRestWebService.java index 08901b863a..d368e5d00b 100644 --- a/Server/src/main/java/org/xdi/oxauth/uma/ws/rs/RptPermissionAuthorizationRestWebService.java +++ b/Server/src/main/java/org/xdi/oxauth/uma/ws/rs/RptPermissionAuthorizationRestWebService.java @@ -1,5 +1,6 @@ package org.xdi.oxauth.uma.ws.rs; +import com.wordnik.swagger.annotations.Api; import org.xdi.oxauth.model.uma.RptAuthorizationRequest; import org.xdi.oxauth.model.uma.UmaConstants; @@ -13,11 +14,12 @@ import javax.ws.rs.core.Response; /** - * The endpoint at which the requester asks for authorizationto have a new permission. + * The endpoint at which the requester asks for authorization to have a new permission. * * @author Yuriy Movchan Date: 10/25/2012 */ @Path("/requester/perm") +@Api(value="/requester/perm", description = "RPT authorization endpoint. RPT is authorized with new permission(s).") public interface RptPermissionAuthorizationRestWebService { @POST diff --git a/Server/src/main/java/org/xdi/oxauth/uma/ws/rs/RptRestWebService.java b/Server/src/main/java/org/xdi/oxauth/uma/ws/rs/RptRestWebService.java index afaeda5659..fec34e6697 100644 --- a/Server/src/main/java/org/xdi/oxauth/uma/ws/rs/RptRestWebService.java +++ b/Server/src/main/java/org/xdi/oxauth/uma/ws/rs/RptRestWebService.java @@ -1,5 +1,6 @@ package org.xdi.oxauth.uma.ws.rs; +import com.wordnik.swagger.annotations.Api; import org.xdi.oxauth.model.uma.UmaConstants; import javax.ws.rs.HeaderParam; @@ -15,6 +16,7 @@ * @author Yuriy Movchan Date: 10/16/2012 */ @Path("/requester/rpt") +@Api(value = "/requester/rpt", description = "The endpoint at which the requester asks the AM to issue an RPT") public interface RptRestWebService { @POST diff --git a/Server/src/main/java/org/xdi/oxauth/uma/ws/rs/RptStatusRestWebService.java b/Server/src/main/java/org/xdi/oxauth/uma/ws/rs/RptStatusRestWebService.java index b032df45be..e4ceb2f171 100644 --- a/Server/src/main/java/org/xdi/oxauth/uma/ws/rs/RptStatusRestWebService.java +++ b/Server/src/main/java/org/xdi/oxauth/uma/ws/rs/RptStatusRestWebService.java @@ -1,5 +1,6 @@ package org.xdi.oxauth.uma.ws.rs; +import com.wordnik.swagger.annotations.Api; import org.xdi.oxauth.model.uma.RptStatusRequest; import org.xdi.oxauth.model.uma.UmaConstants; @@ -20,6 +21,8 @@ * Date: 10/23/2012 */ @Path("/host/status") +@Api(value="/host/status", description = "The endpoint at which the host requests the status of an RPT presented to it by a requester." + + " The endpoint is RPT introspection profile implementation defined by UMA specification") public interface RptStatusRestWebService { @POST diff --git a/Server/src/main/java/org/xdi/oxauth/uma/ws/rs/ScopeIconWS.java b/Server/src/main/java/org/xdi/oxauth/uma/ws/rs/ScopeIconWS.java index a34e716ec3..405f02984d 100644 --- a/Server/src/main/java/org/xdi/oxauth/uma/ws/rs/ScopeIconWS.java +++ b/Server/src/main/java/org/xdi/oxauth/uma/ws/rs/ScopeIconWS.java @@ -1,5 +1,6 @@ package org.xdi.oxauth.uma.ws.rs; +import com.wordnik.swagger.annotations.Api; import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang.StringUtils; import org.jboss.seam.annotations.In; @@ -28,6 +29,7 @@ @Path("/uma/scopes/icons") @Name("umaScopeIconRestWebService") +@Api(value= "/uma/scopes/icons", description = "UMA Scope Icon endpoint provides scope icon by scope id.") public class ScopeIconWS { @Logger diff --git a/Server/src/main/java/org/xdi/oxauth/uma/ws/rs/ScopeWS.java b/Server/src/main/java/org/xdi/oxauth/uma/ws/rs/ScopeWS.java index f6d1a93833..9be921679f 100644 --- a/Server/src/main/java/org/xdi/oxauth/uma/ws/rs/ScopeWS.java +++ b/Server/src/main/java/org/xdi/oxauth/uma/ws/rs/ScopeWS.java @@ -1,5 +1,6 @@ package org.xdi.oxauth.uma.ws.rs; +import com.wordnik.swagger.annotations.Api; import org.apache.commons.lang.StringUtils; import org.jboss.seam.annotations.In; import org.jboss.seam.annotations.Logger; @@ -25,6 +26,7 @@ */ @Path("/uma/scopes") @Name("umaScopeRestWebService") +@Api(value="/uma/scopes", description = "UMA Scope Endpoint provides scope description (json document) by scope id.") public class ScopeWS { @Logger diff --git a/Server/src/main/java/org/xdi/oxauth/userinfo/ws/rs/UserInfoRestWebService.java b/Server/src/main/java/org/xdi/oxauth/userinfo/ws/rs/UserInfoRestWebService.java index 65eebd8913..4ccb74cc66 100644 --- a/Server/src/main/java/org/xdi/oxauth/userinfo/ws/rs/UserInfoRestWebService.java +++ b/Server/src/main/java/org/xdi/oxauth/userinfo/ws/rs/UserInfoRestWebService.java @@ -1,6 +1,13 @@ package org.xdi.oxauth.userinfo.ws.rs; -import javax.ws.rs.*; +import com.wordnik.swagger.annotations.Api; + +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; import javax.ws.rs.core.SecurityContext; @@ -11,6 +18,7 @@ * @author Javier Rojas Blum Date: 11.29.2011 */ @Path("/oxauth") +@Api(value = "/oxauth", description = "The UserInfo Endpoint is an OAuth 2.0 Protected Resource that returns Claims about the authenticated End-User. To obtain the requested Claims about the End-User, the Client makes a request to the UserInfo Endpoint using an Access Token obtained through OpenID Connect Authentication. These Claims are normally represented by a JSON object that contains a collection of name and value pairs for the Claims. ") public interface UserInfoRestWebService { @GET diff --git a/Server/src/main/java/org/xdi/oxauth/util/ServerUtil.java b/Server/src/main/java/org/xdi/oxauth/util/ServerUtil.java index 663bae5246..35ff7ba06b 100644 --- a/Server/src/main/java/org/xdi/oxauth/util/ServerUtil.java +++ b/Server/src/main/java/org/xdi/oxauth/util/ServerUtil.java @@ -23,6 +23,9 @@ import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ThreadFactory; /** * @author Yuriy Zabrovarnyy @@ -126,6 +129,16 @@ public static String urlDecode(String p_str) { return p_str; } + public static ScheduledExecutorService createExecutor() { + return Executors.newSingleThreadScheduledExecutor(new ThreadFactory() { + public Thread newThread(Runnable p_r) { + Thread thread = new Thread(p_r); + thread.setDaemon(true); + return thread; + } + }); + } + public static ResourceSetPermissionRequest convert(ResourceSetPermission p_permission, ScopeService p_umaScopeService) { if (p_permission != null) { final ResourceSetPermissionRequest result = new ResourceSetPermissionRequest(); diff --git a/Server/src/main/webapp/WEB-INF/web.xml b/Server/src/main/webapp/WEB-INF/web.xml index cf4b97372b..d88646712f 100644 --- a/Server/src/main/webapp/WEB-INF/web.xml +++ b/Server/src/main/webapp/WEB-INF/web.xml @@ -50,6 +50,36 @@ ${web.xml.php-bridge.servlet} @debug@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + javax.faces.DEFAULT_SUFFIX diff --git a/Server/src/main/webapp/authorize.page.xml b/Server/src/main/webapp/authorize.page.xml index 5c45f77b66..36c0095048 100644 --- a/Server/src/main/webapp/authorize.page.xml +++ b/Server/src/main/webapp/authorize.page.xml @@ -38,6 +38,8 @@ value="#{authorizeAction.loginHint}"/> + + diff --git a/Server/src/main/webapp/logout.page.xml b/Server/src/main/webapp/logout.page.xml index 897f4ac320..e1377ec5e9 100644 --- a/Server/src/main/webapp/logout.page.xml +++ b/Server/src/main/webapp/logout.page.xml @@ -7,6 +7,8 @@ + + diff --git a/Server/src/test/resources/conf/oxauth-config.xml b/Server/src/test/resources/conf/oxauth-config.xml index c1f57d0f56..59a6b969df 100644 --- a/Server/src/test/resources/conf/oxauth-config.xml +++ b/Server/src/test/resources/conf/oxauth-config.xml @@ -42,16 +42,13 @@ urn:ietf:params:oauth:grant-type:jwt-bearer - http://example.com/authn/auth_mode/duo - http://example.com/authn/auth_level/10 - http://example.com/authn/auth_mode/toopher - duo - 10 - toopher + https://schema.gluu.org/openid/amr/method/duo + https://schema.gluu.org/openid/amr/level/10 + https://schema.gluu.org/openid/amr/method/toopher public @@ -256,7 +253,7 @@ - + oxAuthClientCustomAttributes oxAuthTrustedClient diff --git a/ShibIdpClient/pom.xml b/ShibIdpClient/pom.xml index 2df0ef0258..04b3f5d39c 100644 --- a/ShibIdpClient/pom.xml +++ b/ShibIdpClient/pom.xml @@ -10,7 +10,7 @@ org.xdi oxauth - 1.3.2.Final + 1.4.1.Final diff --git a/oxAuthStatic/pom.xml b/oxAuthStatic/pom.xml index c764bdc688..fb14248ef6 100644 --- a/oxAuthStatic/pom.xml +++ b/oxAuthStatic/pom.xml @@ -4,7 +4,7 @@ org.xdi oxAuthStatic - 1.3.2.Final + 1.4.1.Final jar oxAuthStatic diff --git a/pom.xml b/pom.xml index 82a25902f4..56277f40fe 100644 --- a/pom.xml +++ b/pom.xml @@ -4,19 +4,19 @@ org.xdi oxauth pom - 1.3.2.Final + 1.4.1.Final oxAuth http://ox.gluu.org UTF-8 3.0.3 - 1.3.2.Final + 1.4.1.Final 1.9.9 1.3 2.3.4.Final 4.2.3 - 1.4.2 + 1.6.5 2.2.2.Final beta3 5.0.1 @@ -581,6 +581,18 @@ 6.3.1 test + + + + com.wordnik + swagger-jaxrs_2.10 + 1.3.7 + + + com.wordnik + swagger-servlet_2.9.1 + 1.3.1 +