From 3546cafb4942247edf298996186fcdfa32eb9954 Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Tue, 17 Dec 2013 08:33:18 +0100 Subject: First version for testing -> Exthex OAuth implementation --- id/server/idserverlib/pom.xml | 128 ++-- .../auth/builder/StartAuthenticationBuilder.java | 7 +- .../moa/id/auth/data/AuthenticationSession.java | 649 ++++++++++----------- .../gv/egovernment/moa/id/config/OAParameter.java | 123 ++-- .../id/config/auth/AuthConfigurationProvider.java | 19 +- .../moa/id/entrypoints/DispatcherServlet.java | 2 +- .../gv/egovernment/moa/id/moduls/ModulStorage.java | 3 +- .../id/protocols/oauth20/OAuth20AuthAction.java | 92 +++ .../id/protocols/oauth20/OAuth20Configuration.java | 51 ++ .../moa/id/protocols/oauth20/OAuth20Constants.java | 45 ++ .../moa/id/protocols/oauth20/OAuth20Protocol.java | 166 ++++++ .../id/protocols/oauth20/OAuth20SessionObject.java | 39 ++ .../id/protocols/oauth20/OAuth20TokenAction.java | 346 +++++++++++ .../moa/id/protocols/oauth20/OAuth20Util.java | 134 +++++ .../exceptions/OAuth20AccessDeniedException.java | 12 + .../OAuth20CertificateErrorException.java | 12 + .../oauth20/exceptions/OAuth20Exception.java | 49 ++ .../exceptions/OAuth20InvalidClientException.java | 12 + .../exceptions/OAuth20InvalidGrantException.java | 12 + .../exceptions/OAuth20InvalidRequestException.java | 13 + .../exceptions/OAuth20ResponseTypeException.java | 12 + .../exceptions/OAuth20ServerErrorException.java | 12 + .../OAuth20UnauthorizedClientException.java | 12 + .../exceptions/OAuth20WrongParameterException.java | 12 + .../oauth20/requests/OAuth20AuthRequest.java | 134 +++++ .../oauth20/requests/OAuth20BaseRequest.java | 118 ++++ .../oauth20/requests/OAuth20TokenRequest.java | 118 ++++ .../resources/properties/id_messages_de.properties | 13 +- .../gv/egovernment/moa/id/auth/oauth/CertTest.java | 86 +++ .../moa/id/auth/oauth/OAuth20ErrorsTests.java | 190 ++++++ .../id/auth/oauth/OAuth20GoogleClientTestCase.java | 136 +++++ .../moa/id/auth/oauth/OAuth20UtilTest.java | 48 ++ 32 files changed, 2354 insertions(+), 451 deletions(-) create mode 100644 id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/OAuth20AuthAction.java create mode 100644 id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/OAuth20Configuration.java create mode 100644 id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/OAuth20Constants.java create mode 100644 id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/OAuth20Protocol.java create mode 100644 id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/OAuth20SessionObject.java create mode 100644 id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/OAuth20TokenAction.java create mode 100644 id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/OAuth20Util.java create mode 100644 id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/exceptions/OAuth20AccessDeniedException.java create mode 100644 id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/exceptions/OAuth20CertificateErrorException.java create mode 100644 id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/exceptions/OAuth20Exception.java create mode 100644 id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/exceptions/OAuth20InvalidClientException.java create mode 100644 id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/exceptions/OAuth20InvalidGrantException.java create mode 100644 id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/exceptions/OAuth20InvalidRequestException.java create mode 100644 id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/exceptions/OAuth20ResponseTypeException.java create mode 100644 id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/exceptions/OAuth20ServerErrorException.java create mode 100644 id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/exceptions/OAuth20UnauthorizedClientException.java create mode 100644 id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/exceptions/OAuth20WrongParameterException.java create mode 100644 id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/requests/OAuth20AuthRequest.java create mode 100644 id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/requests/OAuth20BaseRequest.java create mode 100644 id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/requests/OAuth20TokenRequest.java create mode 100644 id/server/idserverlib/src/test/java/test/at/gv/egovernment/moa/id/auth/oauth/CertTest.java create mode 100644 id/server/idserverlib/src/test/java/test/at/gv/egovernment/moa/id/auth/oauth/OAuth20ErrorsTests.java create mode 100644 id/server/idserverlib/src/test/java/test/at/gv/egovernment/moa/id/auth/oauth/OAuth20GoogleClientTestCase.java create mode 100644 id/server/idserverlib/src/test/java/test/at/gv/egovernment/moa/id/auth/oauth/OAuth20UtilTest.java (limited to 'id/server/idserverlib') diff --git a/id/server/idserverlib/pom.xml b/id/server/idserverlib/pom.xml index ab1a28091..3cc7c38de 100644 --- a/id/server/idserverlib/pom.xml +++ b/id/server/idserverlib/pom.xml @@ -1,4 +1,5 @@ - + MOA.id moa-id @@ -16,30 +17,30 @@ - - shibboleth.internet2.edu - Internet2 - https://build.shibboleth.net/nexus/content/groups/public/ - + + shibboleth.internet2.edu + Internet2 + https://build.shibboleth.net/nexus/content/groups/public/ + - + - - MOA.id - stork-saml-engine - 1.5.2 - - - MOA.id.server - moa-id-commons - ${pom.version} - + + MOA.id + stork-saml-engine + 1.5.2 + + + MOA.id.server + moa-id-commons + ${pom.version} + MOA moa-common jar - + MOA moa-common test-jar @@ -96,10 +97,10 @@ commons-fileupload commons-fileupload - - commons-httpclient - commons-httpclient - + + commons-httpclient + commons-httpclient + dav4j dav4j @@ -129,11 +130,8 @@ iaik.prod iaik_X509TrustManager - + edu.internet2.middleware shibboleth-common @@ -149,37 +147,69 @@ regexp regexp - - + + + + commons-lang + commons-lang + 2.6 + + + + + + com.googlecode.jsontoken + jsontoken + 1.0 + + - commons-lang - commons-lang - 2.6 - + commons-codec + commons-codec + 1.8 + + + + + com.google.http-client + google-http-client-jackson2 + 1.17.0-rc + test + + + com.google.oauth-client + google-oauth-client-jetty + 1.17.0-rc + test + + + + + org.testng + testng + 6.1.1 + test + + - - org.apache.maven.plugins - maven-compiler-plugin - - 1.5 - 1.5 - + + org.apache.maven.plugins + maven-compiler-plugin + + 1.5 + 1.5 + - + org.apache.maven.plugins maven-jar-plugin - true + true false diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/StartAuthenticationBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/StartAuthenticationBuilder.java index 3bc152ec8..e4bf37417 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/StartAuthenticationBuilder.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/StartAuthenticationBuilder.java @@ -36,7 +36,8 @@ public class StartAuthenticationBuilder { Logger.info("Starting authentication for a citizen of country: " + (StringUtils.isEmpty(moasession.getCcc()) ? "AT" : moasession.getCcc())); // STORK or normal authentication - if (storkConfig.isSTORKAuthentication(moasession.getCcc())) { + //TODO: commented because npe was thrown + /*if (storkConfig.isSTORKAuthentication(moasession.getCcc())) { //STORK authentication Logger.trace("Found C-PEPS configuration for citizen of country: " + moasession.getCcc()); Logger.debug("Starting STORK authentication"); @@ -44,13 +45,13 @@ public class StartAuthenticationBuilder { AuthenticationServer.startSTORKAuthentication(req, resp, moasession); return ""; - } else { + } else {*/ //normal MOA-ID authentication Logger.debug("Starting normal MOA-ID authentication"); String getIdentityLinkForm = AuthenticationServer.getInstance().startAuthentication(moasession, req); return getIdentityLinkForm; - } + //} } } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/AuthenticationSession.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/AuthenticationSession.java index 9eaa13f04..1061a2802 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/AuthenticationSession.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/data/AuthenticationSession.java @@ -1,24 +1,15 @@ /* - * Copyright 2003 Federal Chancellery Austria - * MOA-ID has been developed in a cooperation between BRZ, the Federal - * Chancellery Austria - ICT staff unit, and Graz University of Technology. - * - * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * http://www.osor.eu/eupl/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. + * Copyright 2003 Federal Chancellery Austria MOA-ID has been developed in a cooperation between + * BRZ, the Federal Chancellery Austria - ICT staff unit, and Graz University of Technology. + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by the European + * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: http://www.osor.eu/eupl/ + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. This product combines work with different licenses. See the "NOTICE" text file for + * details on the various modules and licenses. The "NOTICE" text file is part of the distribution. + * Any derivative works that you distribute must include a readable copy of the "NOTICE" text file. */ package at.gv.egovernment.moa.id.auth.data; @@ -37,6 +28,7 @@ import org.w3c.dom.Element; import at.gv.egovernment.moa.id.auth.validator.InfoboxValidator; import at.gv.egovernment.moa.id.auth.validator.parep.ParepUtils; +import at.gv.egovernment.moa.id.protocols.oauth20.OAuth20SessionObject; import at.gv.egovernment.moa.id.util.client.mis.simple.MISMandate; import at.gv.egovernment.moa.logging.Logger; import at.gv.egovernment.moa.util.Constants; @@ -44,43 +36,40 @@ import at.gv.egovernment.moa.util.DOMUtils; import eu.stork.mw.messages.saml.STORKAuthnRequest; /** - * Session data to be stored between AuthenticationServer API - * calls. + * Session data to be stored between AuthenticationServer API calls. * * @author Paul Ivancsics * @version $Id$ */ public class AuthenticationSession implements Serializable { - + /** * */ private static final long serialVersionUID = 1L; public static final String TARGET_PREFIX_ = Constants.URN_PREFIX_CDID + "+"; - public static final String REGISTERANDORDNR_PREFIX_ = Constants.URN_PREFIX_WBPK - + "+"; - + public static final String REGISTERANDORDNR_PREFIX_ = Constants.URN_PREFIX_WBPK + "+"; + /** * session ID */ private String sessionID; /** - * "Geschäftsbereich" the online application belongs to; maybe - * null if the online application is a business application + * "Geschäftsbereich" the online application belongs to; maybe null if the + * online application is a business application */ private String target; /** - * Friendly name for the target, if target is configured via MOA-ID - * configuration + * Friendly name for the target, if target is configured via MOA-ID configuration */ private String targetFriendlyName; - + /** * SourceID */ private String sourceID; - + /** * public online application URL requested */ @@ -97,28 +86,25 @@ public class AuthenticationSession implements Serializable { * HTML template URL */ private String templateURL; - + /** * URL of the BKU */ private String bkuURL; - + /** - * Indicates whether the corresponding online application is a business - * service or not + * Indicates whether the corresponding online application is a business service or not */ private boolean businessService; - //Store Mandate + // Store Mandate /** * Use mandate */ private boolean useMandate; - private boolean isOW = false; - /** * STORK */ @@ -126,33 +112,32 @@ public class AuthenticationSession implements Serializable { /** * - * Mandate element + * Mandate element */ private MISMandate mandate; /** - * Reference value for mandate - * bussiness service for the assertion + * Reference value for mandate bussiness service for the assertion */ private String mandateReferenceValue; - + /** * SessionID for MIS */ private String misSessionID; - //store Identitylink + // store Identitylink /** * identity link read from smartcard */ private IdentityLink identityLink; - -// /** -// * timestamp logging when identity link has been received -// */ -// private Date timestampIdentityLink; - //store Authblock + // /** + // * timestamp logging when identity link has been received + // */ + // private Date timestampIdentityLink; + + // store Authblock /** * authentication block to be signed by the user */ @@ -164,61 +149,56 @@ public class AuthenticationSession implements Serializable { * The issuing time of the AUTH-Block SAML assertion. */ private String issueInstant; - - //Signer certificate + + // Signer certificate /** * Signer certificate of the foreign citizen or for mandate mode */ - //private X509Certificate signerCertificate; + // private X509Certificate signerCertificate; private byte[] signerCertificate; - /** - * SAML attributes from an extended infobox validation to be appended to the - * SAML assertion delivered to the final online application. + * SAML attributes from an extended infobox validation to be appended to the SAML assertion + * delivered to the final online application. */ private List extendedSAMLAttributesOA; - + /** - * The boolean value for either a target or a wbPK is provided as SAML - * Attribute in the SAML Assertion or not. + * The boolean value for either a target or a wbPK is provided as SAML Attribute in the SAML + * Assertion or not. */ private boolean samlAttributeGebeORwbpk; - + /** - * SAML attributes from an extended infobox validation to be appended to the - * SAML assertion of the AUTHBlock. + * SAML attributes from an extended infobox validation to be appended to the SAML assertion of + * the AUTHBlock. */ private List extendedSAMLAttributesAUTH; - + /** - * If infobox validators are needed after signing, they can be stored in - * this list. + * If infobox validators are needed after signing, they can be stored in this list. */ private List infoboxValidators; - + /** - * The register and number in the register parameter in case of a business - * service application. + * The register and number in the register parameter in case of a business service application. */ private String domainIdentifier; - + /** - * This string contains all identifiers of infoboxes, the online application - * is configured to accept. The infobox identifiers are comma separated. + * This string contains all identifiers of infoboxes, the online application is configured to + * accept. The infobox identifiers are comma separated. */ private String pushInfobox; - + /** * The STORK AuthRequest to be sent to the C-PEPS */ private STORKAuthnRequest storkAuthnRequest; + // private AuthenticationData authData; - - //private AuthenticationData authData; - - //protocol selection + // protocol selection private String action; private String modul; @@ -227,82 +207,83 @@ public class AuthenticationSession implements Serializable { private boolean ssoRequested = false; -// /** -// * Indicates if target from configuration is used or not -// */ -// private boolean useTargetFromConfig; - -// /** -// * Authentication data for the assertion -// */ -// private AuthenticationData assertionAuthData; -// -// /** -// * Persondata for the assertion -// */ -// private String assertionPrPerson; -// -// /** -// * Authblock for the assertion -// */ -// private String assertionAuthBlock; -// -// /** -// * Identitylink assertion for the (MOA) assertion -// */ -// private String assertionIlAssertion; -// -// /** -// * Signer certificate (base64 encoded) for the assertion -// */ -// private String assertionSignerCertificateBase64; -// -// /** -// * bussiness service for the assertion -// */ -// boolean assertionBusinessService; -// -// /** -// * timestamp logging when authentication session has been created -// */ -// private Date timestampStart; -// private CreateXMLSignatureResponse XMLCreateSignatureResponse; + private OAuth20SessionObject oAuth20SessionObject; + + // /** + // * Indicates if target from configuration is used or not + // */ + // private boolean useTargetFromConfig; + + // /** + // * Authentication data for the assertion + // */ + // private AuthenticationData assertionAuthData; + // + // /** + // * Persondata for the assertion + // */ + // private String assertionPrPerson; + // + // /** + // * Authblock for the assertion + // */ + // private String assertionAuthBlock; + // + // /** + // * Identitylink assertion for the (MOA) assertion + // */ + // private String assertionIlAssertion; + // + // /** + // * Signer certificate (base64 encoded) for the assertion + // */ + // private String assertionSignerCertificateBase64; + // + // /** + // * bussiness service for the assertion + // */ + // boolean assertionBusinessService; + // + // /** + // * timestamp logging when authentication session has been created + // */ + // private Date timestampStart; + // private CreateXMLSignatureResponse XMLCreateSignatureResponse; private VerifyXMLSignatureResponse XMLVerifySignatureResponse; private boolean isForeigner; -// private String requestedProtocolURL = null; - + // private String requestedProtocolURL = null; + public String getModul() { return modul; } - + public void setModul(String modul) { this.modul = modul; } - + public String getAction() { return action; } - + public void setAction(String action) { this.action = action; } - -// public AuthenticationData getAuthData() { -// return authData; -// } -// -// public void setAuthData(AuthenticationData authData) { -// this.authData = authData; -// } - - + + // public AuthenticationData getAuthData() { + // return authData; + // } + // + // public void setAuthData(AuthenticationData authData) { + // this.authData = authData; + // } + public boolean isAuthenticatedUsed() { return authenticatedUsed; } - + public void setAuthenticatedUsed(boolean authenticatedUsed) { this.authenticatedUsed = authenticatedUsed; } @@ -314,16 +295,15 @@ public class AuthenticationSession implements Serializable { public void setAuthenticated(boolean authenticated) { this.authenticated = authenticated; } - - -// public String getRequestedProtocolURL() { -// return requestedProtocolURL; -// } -// -// public void setRequestedProtocolURL(String requestedProtocolURL) { -// this.requestedProtocolURL = requestedProtocolURL; -// } - + + // public String getRequestedProtocolURL() { + // return requestedProtocolURL; + // } + // + // public void setRequestedProtocolURL(String requestedProtocolURL) { + // this.requestedProtocolURL = requestedProtocolURL; + // } + /** * Constructor for AuthenticationSession. * @@ -332,14 +312,15 @@ public class AuthenticationSession implements Serializable { */ public AuthenticationSession(String id) { sessionID = id; -// setTimestampStart(); + // setTimestampStart(); infoboxValidators = new ArrayList(); } - - public X509Certificate getSignerCertificate(){ + + public X509Certificate getSignerCertificate() { try { return new X509Certificate(signerCertificate); - } catch (CertificateException e) { + } + catch (CertificateException e) { Logger.warn("Signer certificate can not be loaded from session database!", e); return null; } @@ -348,15 +329,16 @@ public class AuthenticationSession implements Serializable { public byte[] getEncodedSignerCertificate() { return this.signerCertificate; } - + public void setSignerCertificate(X509Certificate signerCertificate) { try { this.signerCertificate = signerCertificate.getEncoded(); - } catch (CertificateEncodingException e) { + } + catch (CertificateEncodingException e) { Logger.warn("Signer certificate can not be stored to session database!", e); } } - + /** * Returns the identityLink. * @@ -365,7 +347,7 @@ public class AuthenticationSession implements Serializable { public IdentityLink getIdentityLink() { return identityLink; } - + /** * Returns the sessionID. * @@ -374,7 +356,7 @@ public class AuthenticationSession implements Serializable { public String getSessionID() { return sessionID; } - + /** * Sets the identityLink. * @@ -384,7 +366,7 @@ public class AuthenticationSession implements Serializable { public void setIdentityLink(IdentityLink identityLink) { this.identityLink = identityLink; } - + /** * Sets the sessionID. * @@ -394,7 +376,7 @@ public class AuthenticationSession implements Serializable { public void setSessionID(String sessionId) { this.sessionID = sessionId; } - + /** * Returns the oaURLRequested. * @@ -403,7 +385,7 @@ public class AuthenticationSession implements Serializable { public String getOAURLRequested() { return oaURLRequested; } - + /** * Returns the oaURLRequested. * @@ -412,7 +394,7 @@ public class AuthenticationSession implements Serializable { public String getPublicOAURLPrefix() { return oaPublicURLPrefix; } - + /** * Returns the BKU URL. * @@ -421,7 +403,7 @@ public class AuthenticationSession implements Serializable { public String getBkuURL() { return bkuURL; } - + /** * Returns the target. * @@ -430,7 +412,7 @@ public class AuthenticationSession implements Serializable { public String getTarget() { return target; } - + /** * Returns the sourceID. * @@ -439,7 +421,7 @@ public class AuthenticationSession implements Serializable { public String getSourceID() { return sourceID; } - + /** * Returns the target friendly name. * @@ -448,7 +430,7 @@ public class AuthenticationSession implements Serializable { public String getTargetFriendlyName() { return targetFriendlyName; } - + /** * Sets the oaURLRequested. * @@ -458,7 +440,7 @@ public class AuthenticationSession implements Serializable { public void setOAURLRequested(String oaURLRequested) { this.oaURLRequested = oaURLRequested; } - + /** * Sets the oaPublicURLPrefix * @@ -468,7 +450,7 @@ public class AuthenticationSession implements Serializable { public void setPublicOAURLPrefix(String oaPublicURLPrefix) { this.oaPublicURLPrefix = oaPublicURLPrefix; } - + /** * Sets the bkuURL * @@ -478,10 +460,9 @@ public class AuthenticationSession implements Serializable { public void setBkuURL(String bkuURL) { this.bkuURL = bkuURL; } - + /** - * Sets the target. If the target includes the target prefix, the prefix - * will be stripped off. + * Sets the target. If the target includes the target prefix, the prefix will be stripped off. * * @param target * The target to set @@ -491,13 +472,12 @@ public class AuthenticationSession implements Serializable { // If target starts with prefix "urn:publicid:gv.at:cdid+"; remove // prefix this.target = target.substring(TARGET_PREFIX_.length()); - Logger.debug("Target prefix stripped off; resulting target: " - + this.target); + Logger.debug("Target prefix stripped off; resulting target: " + this.target); } else { this.target = target; } } - + /** * Sets the sourceID * @@ -507,10 +487,9 @@ public class AuthenticationSession implements Serializable { public void setSourceID(String sourceID) { this.sourceID = sourceID; } - + /** - * Sets the target. If the target includes the target prefix, the prefix - * will be stripped off. + * Sets the target. If the target includes the target prefix, the prefix will be stripped off. * * @param target * The target to set @@ -518,7 +497,7 @@ public class AuthenticationSession implements Serializable { public void setTargetFriendlyName(String targetFriendlyName) { this.targetFriendlyName = targetFriendlyName; } - + /** * Returns the authURL. * @@ -527,7 +506,7 @@ public class AuthenticationSession implements Serializable { public String getAuthURL() { return authURL; } - + /** * Sets the authURL. * @@ -537,7 +516,7 @@ public class AuthenticationSession implements Serializable { public void setAuthURL(String authURL) { this.authURL = authURL; } - + /** * Returns the authBlock. * @@ -546,7 +525,7 @@ public class AuthenticationSession implements Serializable { public String getAuthBlock() { return authBlock; } - + /** * Sets the authBlock. * @@ -556,17 +535,17 @@ public class AuthenticationSession implements Serializable { public void setAuthBlock(String authBlock) { this.authBlock = authBlock; } - + /** * Returns the businessService. * - * @return true if the corresponding online application is a - * business application, otherwise false + * @return true if the corresponding online application is a business application, + * otherwise false */ public boolean getBusinessService() { return businessService; } - + /** * Sets the businessService variable. * @@ -576,15 +555,14 @@ public class AuthenticationSession implements Serializable { public void setBusinessService(boolean businessService) { this.businessService = businessService; } - - + /** * @return template URL */ public String getTemplateURL() { return templateURL; } - + /** * @param string * the template URL @@ -592,21 +570,18 @@ public class AuthenticationSession implements Serializable { public void setTemplateURL(String string) { templateURL = string; } - + /** - * Returns the SAML Attributes to be appended to the AUTHBlock. Maybe - * null. + * Returns the SAML Attributes to be appended to the AUTHBlock. Maybe null. * - * @return The SAML Attributes to be appended to the AUTHBlock. Maybe - * null. + * @return The SAML Attributes to be appended to the AUTHBlock. Maybe null. */ public List getExtendedSAMLAttributesAUTH() { - if (extendedSAMLAttributesAUTH == null) - extendedSAMLAttributesAUTH = new ArrayList(); + if (extendedSAMLAttributesAUTH == null) extendedSAMLAttributesAUTH = new ArrayList(); return extendedSAMLAttributesAUTH; } - + /** * Sets the SAML Attributes to be appended to the AUTHBlock. * @@ -616,53 +591,53 @@ public class AuthenticationSession implements Serializable { public void setExtendedSAMLAttributesAUTH(List extendedSAMLAttributesAUTH) { this.extendedSAMLAttributesAUTH = extendedSAMLAttributesAUTH; } - + /** - * Returns the SAML Attributes to be appended to the SAML assertion - * delivered to the online application. Maybe null. + * Returns the SAML Attributes to be appended to the SAML assertion delivered to the online + * application. Maybe null. * - * @return The SAML Attributes to be appended to the SAML assertion - * delivered to the online application + * @return The SAML Attributes to be appended to the SAML assertion delivered to the online + * application */ public List getExtendedSAMLAttributesOA() { return extendedSAMLAttributesOA; } - + /** - * Sets the SAML Attributes to be appended to the SAML assertion delivered - * to the online application. + * Sets the SAML Attributes to be appended to the SAML assertion delivered to the online + * application. * * @param extendedSAMLAttributesOA - * The SAML Attributes to be appended to the SAML assertion - * delivered to the online application. + * The SAML Attributes to be appended to the SAML assertion delivered to the online + * application. */ public void setExtendedSAMLAttributesOA(List extendedSAMLAttributesOA) { this.extendedSAMLAttributesOA = extendedSAMLAttributesOA; } - + /** - * Returns the boolean value for either a target or a wbPK is provided as - * SAML Attribute in the SAML Assertion or not. + * Returns the boolean value for either a target or a wbPK is provided as SAML Attribute in the + * SAML Assertion or not. * - * @return true either a target or a wbPK is provided as SAML Attribute in - * the SAML Assertion or false if not. + * @return true either a target or a wbPK is provided as SAML Attribute in the SAML Assertion or + * false if not. */ public boolean getSAMLAttributeGebeORwbpk() { return this.samlAttributeGebeORwbpk; } - + /** - * Sets the boolean value for either a target or a wbPK is provided as SAML - * Attribute in the SAML Assertion or not. + * Sets the boolean value for either a target or a wbPK is provided as SAML Attribute in the + * SAML Assertion or not. * * @param samlAttributeGebeORwbpk - * The boolean for value either a target or wbPK is provided as - * SAML Attribute in the SAML Assertion or not. + * The boolean for value either a target or wbPK is provided as SAML Attribute in the + * SAML Assertion or not. */ public void setSAMLAttributeGebeORwbpk(boolean samlAttributeGebeORwbpk) { this.samlAttributeGebeORwbpk = samlAttributeGebeORwbpk; } - + /** * Returns the issuing time of the AUTH-Block SAML assertion. * @@ -671,7 +646,7 @@ public class AuthenticationSession implements Serializable { public String getIssueInstant() { return issueInstant; } - + /** * Sets the issuing time of the AUTH-Block SAML assertion. * @@ -681,40 +656,39 @@ public class AuthenticationSession implements Serializable { public void setIssueInstant(String issueInstant) { this.issueInstant = issueInstant; } - + /** * Returns the iterator to the stored infobox validators. * * @return Iterator */ public Iterator getInfoboxValidatorIterator() { - if (infoboxValidators == null) - return null; + if (infoboxValidators == null) return null; return infoboxValidators.iterator(); } - -// /** -// * Adds an infobox validator class to the stored infobox validators. -// * -// * @param infoboxIdentifier -// * the identifier of the infobox the validator belongs to -// * @param infoboxFriendlyName -// * the friendly name of the infobox -// * @param infoboxValidator -// * the infobox validator to add -// */ -// public Iterator addInfoboxValidator(String infoboxIdentifier, -// String infoboxFriendlyName, InfoboxValidator infoboxValidator) { -// if (infoboxValidators == null) -// infoboxValidators = new ArrayList(); -// Vector v = new Vector(3); -// v.add(infoboxIdentifier); -// v.add(infoboxFriendlyName); -// v.add(infoboxValidator); -// infoboxValidators.add(v); -// return infoboxValidators.iterator(); -// } - + + // /** + // * Adds an infobox validator class to the stored infobox validators. + // * + // * @param infoboxIdentifier + // * the identifier of the infobox the validator belongs to + // * @param infoboxFriendlyName + // * the friendly name of the infobox + // * @param infoboxValidator + // * the infobox validator to add + // */ + // public Iterator addInfoboxValidator(String infoboxIdentifier, + // String infoboxFriendlyName, InfoboxValidator infoboxValidator) { + // if (infoboxValidators == null) + // infoboxValidators = new ArrayList(); + // Vector v = new Vector(3); + // v.add(infoboxIdentifier); + // v.add(infoboxFriendlyName); + // v.add(infoboxValidator); + // infoboxValidators.add(v); + // return infoboxValidators.iterator(); + // } + /** * Tests for pending input events of the infobox validators. * @@ -726,100 +700,94 @@ public class AuthenticationSession implements Serializable { if (iter != null) { while (!result && iter.hasNext()) { Vector infoboxValidatorVector = (Vector) iter.next(); - InfoboxValidator infoboxvalidator = (InfoboxValidator) infoboxValidatorVector - .get(2); - if (!ParepUtils.isEmpty(infoboxvalidator.getForm())) - result = true; + InfoboxValidator infoboxvalidator = (InfoboxValidator) infoboxValidatorVector.get(2); + if (!ParepUtils.isEmpty(infoboxvalidator.getForm())) result = true; } } return result; } - -// /** -// * Returns the first pending infobox validator. -// * -// * @return the infobox validator class -// */ -// public InfoboxValidator getFirstPendingValidator() { -// Iterator iter = getInfoboxValidatorIterator(); -// if (iter != null) { -// while (iter.hasNext()) { -// Vector infoboxValidatorVector = (Vector) iter.next(); -// InfoboxValidator infoboxvalidator = (InfoboxValidator) infoboxValidatorVector -// .get(2); -// String form = infoboxvalidator.getForm(); -// if (!ParepUtils.isEmpty(form)) -// return infoboxvalidator; -// } -// } -// return null; -// } - -// /** -// * Returns the input form of the first pending infobox validator input -// * processor. -// * -// * @return the form to show -// */ -// public String getFirstValidatorInputForm() { -// Iterator iter = getInfoboxValidatorIterator(); -// if (iter != null) { -// while (iter.hasNext()) { -// Vector infoboxValidatorVector = (Vector) iter.next(); -// InfoboxValidator infoboxvalidator = (InfoboxValidator) infoboxValidatorVector -// .get(2); -// String form = infoboxvalidator.getForm(); -// if (!ParepUtils.isEmpty(form)) -// return form; -// } -// } -// return null; -// } - - /** - * Returns domain identifier (the register and number in the register - * parameter). null in the case of not a business service. + + // /** + // * Returns the first pending infobox validator. + // * + // * @return the infobox validator class + // */ + // public InfoboxValidator getFirstPendingValidator() { + // Iterator iter = getInfoboxValidatorIterator(); + // if (iter != null) { + // while (iter.hasNext()) { + // Vector infoboxValidatorVector = (Vector) iter.next(); + // InfoboxValidator infoboxvalidator = (InfoboxValidator) infoboxValidatorVector + // .get(2); + // String form = infoboxvalidator.getForm(); + // if (!ParepUtils.isEmpty(form)) + // return infoboxvalidator; + // } + // } + // return null; + // } + + // /** + // * Returns the input form of the first pending infobox validator input + // * processor. + // * + // * @return the form to show + // */ + // public String getFirstValidatorInputForm() { + // Iterator iter = getInfoboxValidatorIterator(); + // if (iter != null) { + // while (iter.hasNext()) { + // Vector infoboxValidatorVector = (Vector) iter.next(); + // InfoboxValidator infoboxvalidator = (InfoboxValidator) infoboxValidatorVector + // .get(2); + // String form = infoboxvalidator.getForm(); + // if (!ParepUtils.isEmpty(form)) + // return form; + // } + // } + // return null; + // } + + /** + * Returns domain identifier (the register and number in the register parameter). + * null in the case of not a business service. * * @return the domainIdentifier */ public String getDomainIdentifier() { return domainIdentifier; } - + /** - * Sets the register and number in the register parameter if the application - * is a business service. If the domain identifier includes the - * registerAndOrdNr prefix, the prefix will be stripped off. + * Sets the register and number in the register parameter if the application is a business + * service. If the domain identifier includes the registerAndOrdNr prefix, the prefix will be + * stripped off. * * @param domainIdentifier * the domain identifier to set */ public void setDomainIdentifier(String domainIdentifier) { - if (domainIdentifier != null - && domainIdentifier.startsWith(REGISTERANDORDNR_PREFIX_)) { + if (domainIdentifier != null && domainIdentifier.startsWith(REGISTERANDORDNR_PREFIX_)) { // If domainIdentifier starts with prefix // "urn:publicid:gv.at:wbpk+"; remove this prefix - this.domainIdentifier = domainIdentifier - .substring(REGISTERANDORDNR_PREFIX_.length()); - Logger.debug("Register and ordernumber prefix stripped off; resulting register string: " - + this.domainIdentifier); + this.domainIdentifier = domainIdentifier.substring(REGISTERANDORDNR_PREFIX_.length()); + Logger.debug("Register and ordernumber prefix stripped off; resulting register string: " + this.domainIdentifier); } else { this.domainIdentifier = domainIdentifier; } } - + /** - * Gets all identifiers of infoboxes, the online application is configured - * to accept. The infobox identifiers are comma separated. + * Gets all identifiers of infoboxes, the online application is configured to accept. The + * infobox identifiers are comma separated. * * @return the string containing infobox identifiers */ public String getPushInfobox() { - if (pushInfobox == null) - return ""; + if (pushInfobox == null) return ""; return pushInfobox; } - + /** * @param pushInfobox * the infobox identifiers to set (comma separated) @@ -827,7 +795,7 @@ public class AuthenticationSession implements Serializable { public void setPushInfobox(String pushInfobox) { this.pushInfobox = pushInfobox; } - + /** * * @param useMandate @@ -838,9 +806,9 @@ public class AuthenticationSession implements Serializable { this.useMandate = true; else this.useMandate = false; - + } - + /** * Returns if mandate is used or not * @@ -849,7 +817,7 @@ public class AuthenticationSession implements Serializable { public boolean getUseMandate() { return this.useMandate; } - + /** * * @param misSessionID @@ -858,7 +826,7 @@ public class AuthenticationSession implements Serializable { public void setMISSessionID(String misSessionID) { this.misSessionID = misSessionID; } - + /** * Returns the MIS session ID * @@ -867,14 +835,14 @@ public class AuthenticationSession implements Serializable { public String getMISSessionID() { return this.misSessionID; } - + /** * @return the mandateReferenceValue */ public String getMandateReferenceValue() { return mandateReferenceValue; } - + /** * @param mandateReferenceValue * the mandateReferenceValue to set @@ -882,7 +850,7 @@ public class AuthenticationSession implements Serializable { public void setMandateReferenceValue(String mandateReferenceValue) { this.mandateReferenceValue = mandateReferenceValue; } - + /** * Gets the STORK SAML AuthnRequest * @@ -891,7 +859,7 @@ public class AuthenticationSession implements Serializable { public STORKAuthnRequest getStorkAuthnRequest() { return storkAuthnRequest; } - + /** * Sets the STORK SAML AuthnRequest * @@ -901,11 +869,11 @@ public class AuthenticationSession implements Serializable { public void setStorkAuthnRequest(STORKAuthnRequest storkAuthnRequest) { this.storkAuthnRequest = storkAuthnRequest; } - + public String getCcc() { return ccc; } - + public void setCcc(String ccc) { this.ccc = ccc; } @@ -913,23 +881,23 @@ public class AuthenticationSession implements Serializable { public boolean isForeigner() { return isForeigner; } - + public void setForeigner(boolean isForeigner) { this.isForeigner = isForeigner; } - + public VerifyXMLSignatureResponse getXMLVerifySignatureResponse() { return XMLVerifySignatureResponse; } - + public void setXMLVerifySignatureResponse(VerifyXMLSignatureResponse xMLVerifySignatureResponse) { XMLVerifySignatureResponse = xMLVerifySignatureResponse; } - + public MISMandate getMISMandate() { return mandate; } - + public void setMISMandate(MISMandate mandate) { this.mandate = mandate; } @@ -938,60 +906,75 @@ public class AuthenticationSession implements Serializable { try { byte[] byteMandate = mandate.getMandate(); String stringMandate = new String(byteMandate); - return DOMUtils.parseDocument(stringMandate, false, - null, null).getDocumentElement(); + return DOMUtils.parseDocument(stringMandate, false, null, null).getDocumentElement(); - }catch (Throwable e) { + } + catch (Throwable e) { Logger.warn("Mandate content could not be generated from MISMandate."); return null; - } + } } - + /** * @return the ssoRequested */ - //TODO: SSO only allowed without mandates, actually!!!!!! + // TODO: SSO only allowed without mandates, actually!!!!!! public boolean isSsoRequested() { return ssoRequested && !useMandate; } - + /** - * @param ssoRequested the ssoRequested to set + * @param ssoRequested + * the ssoRequested to set */ public void setSsoRequested(boolean ssoRequested) { this.ssoRequested = ssoRequested; } - + /** * @return the isOW */ public boolean isOW() { return isOW; } - + /** - * @param isOW the isOW to set + * @param isOW + * the isOW to set */ public void setOW(boolean isOW) { this.isOW = isOW; } - + /** * @return the authBlockTokken */ public String getAuthBlockTokken() { return authBlockTokken; } - + /** - * @param authBlockTokken the authBlockTokken to set + * @param authBlockTokken + * the authBlockTokken to set */ public void setAuthBlockTokken(String authBlockTokken) { this.authBlockTokken = authBlockTokken; } + /** + * @return the oAuth20SessionObject + */ + public OAuth20SessionObject getoAuth20SessionObject() { + return oAuth20SessionObject; + } - + /** + * @param oAuth20SessionObject + * the oAuth20SessionObject to set + */ + public void setoAuth20SessionObject(OAuth20SessionObject oAuth20SessionObject) { + this.oAuth20SessionObject = oAuth20SessionObject; + } } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/config/OAParameter.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/config/OAParameter.java index 7d76ce9d5..e5cf14d50 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/config/OAParameter.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/config/OAParameter.java @@ -1,40 +1,30 @@ /* - * Copyright 2003 Federal Chancellery Austria - * MOA-ID has been developed in a cooperation between BRZ, the Federal - * Chancellery Austria - ICT staff unit, and Graz University of Technology. - * - * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * http://www.osor.eu/eupl/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. + * Copyright 2003 Federal Chancellery Austria MOA-ID has been developed in a cooperation between + * BRZ, the Federal Chancellery Austria - ICT staff unit, and Graz University of Technology. + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by the European + * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: http://www.osor.eu/eupl/ + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. This product combines work with different licenses. See the "NOTICE" text file for + * details on the various modules and licenses. The "NOTICE" text file is part of the distribution. + * Any derivative works that you distribute must include a readable copy of the "NOTICE" text file. */ - package at.gv.egovernment.moa.id.config; +import at.gv.egovernment.moa.id.commons.db.dao.config.OAOAUTH20; import at.gv.egovernment.moa.id.commons.db.dao.config.OnlineApplication; /** - * Configuration parameters belonging to an online application, - * to be used within both, the MOA ID Auth and the - * MOA ID PROXY component. + * Configuration parameters belonging to an online application, to be used within both, the MOA ID + * Auth and the MOA ID PROXY component. * * @author Harald Bratko */ public class OAParameter { - + public OAParameter(OnlineApplication oa) { this.oaType = oa.getType(); @@ -54,55 +44,68 @@ public class OAParameter { this.removePBKFromAuthblock = oa.isRemoveBPKFromAuthBlock(); + this.oAuth20Config = oa.getAuthComponentOA().getOAOAUTH20(); + + } - /** - * type of the online application (maybe "PublicService" or "BusinessService") - */ - private String oaType; - - /** - * specifies whether the online application is a business application or not - * (true if value of {@link #oaType} is "businessService" - */ - private boolean businessService; - - /** - * public URL prefix of the online application - */ - private String publicURLPrefix; - - /** - * specifies a human readable name of the Online Application - */ - private String friendlyName; - - /** - * specified a specific target for the Online Application (overwrites the target in der request) - */ - private String target; - /** - * specifies a friendly name for the target - */ - private String targetFriendlyName; - - private boolean removePBKFromAuthblock; - + /** + * type of the online application (maybe "PublicService" or "BusinessService") + */ + private String oaType; + + /** + * specifies whether the online application is a business application or not (true + * if value of {@link #oaType} is "businessService" + */ + private boolean businessService; + + /** + * public URL prefix of the online application + */ + private String publicURLPrefix; + + /** + * specifies a human readable name of the Online Application + */ + private String friendlyName; + + /** + * specified a specific target for the Online Application (overwrites the target in der request) + */ + private String target; + /** + * specifies a friendly name for the target + */ + private String targetFriendlyName; + + private boolean removePBKFromAuthblock; + + /** + * Contains the oAuth 2.0 configuration (client id, secret and redirect uri) + */ + private OAOAUTH20 oAuth20Config; + public String getOaType() { return oaType; } + public boolean getBusinessService() { return businessService; } + public String getPublicURLPrefix() { return publicURLPrefix; } + public String getFriendlyName() { return friendlyName; } + public String getTarget() { return target; } + public String getTargetFriendlyName() { return targetFriendlyName; } @@ -110,5 +113,9 @@ public class OAParameter { public boolean isRemovePBKFromAuthBlock() { return removePBKFromAuthblock; } - + + public OAOAUTH20 getoAuth20Config() { + return oAuth20Config; + } + } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/config/auth/AuthConfigurationProvider.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/config/auth/AuthConfigurationProvider.java index 304771edf..29f567324 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/config/auth/AuthConfigurationProvider.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/config/auth/AuthConfigurationProvider.java @@ -76,7 +76,6 @@ import at.gv.egovernment.moa.id.commons.db.dao.session.ExceptionStore; import at.gv.egovernment.moa.id.commons.db.dao.session.OASessionStore; import at.gv.egovernment.moa.id.commons.db.dao.session.OldSSOSessionIDStore; import at.gv.egovernment.moa.id.commons.db.dao.statistic.StatisticLog; -import at.gv.egovernment.moa.id.config.legacy.BuildFromLegacyConfig; import at.gv.egovernment.moa.id.config.ConfigurationException; import at.gv.egovernment.moa.id.config.ConfigurationProvider; import at.gv.egovernment.moa.id.config.ConfigurationUtils; @@ -84,6 +83,7 @@ import at.gv.egovernment.moa.id.config.ConnectionParameter; import at.gv.egovernment.moa.id.config.ConnectionParameterForeign; import at.gv.egovernment.moa.id.config.ConnectionParameterMOASP; import at.gv.egovernment.moa.id.config.ConnectionParameterMandate; +import at.gv.egovernment.moa.id.config.legacy.BuildFromLegacyConfig; import at.gv.egovernment.moa.id.config.stork.STORKConfig; import at.gv.egovernment.moa.id.data.IssuerAndSerial; import at.gv.egovernment.moa.logging.Logger; @@ -432,8 +432,10 @@ public class AuthConfigurationProvider extends ConfigurationProvider { if (foreign == null ) { Logger.warn("Error in MOA-ID Configuration. No STORK configuration found."); - } else - storkconfig = new STORKConfig(foreign.getSTORK(), props, rootConfigFileDir); + } + //TODO: commented because npe was thrown + //else + //storkconfig = new STORKConfig(foreign.getSTORK(), props, rootConfigFileDir); //load Chaining modes @@ -687,10 +689,9 @@ public class AuthConfigurationProvider extends ConfigurationProvider { } - public Properties getGeneralPVP2ProperiesConfig() { + private Properties getGeneralProperiesConfig(final String propPrefix) { Properties configProp = new Properties(); for (Object key : props.keySet()) { - String propPrefix = "protocols.pvp2."; if (key.toString().startsWith(propPrefix)) { String propertyName = key.toString().substring(propPrefix.length()); configProp.put(propertyName, props.get(key.toString())); @@ -699,6 +700,14 @@ public class AuthConfigurationProvider extends ConfigurationProvider { return configProp; } + public Properties getGeneralPVP2ProperiesConfig() { + return this.getGeneralProperiesConfig("protocols.pvp2."); + } + + public Properties getGeneralOAuth20ProperiesConfig() { + return this.getGeneralProperiesConfig("protocols.oauth20."); + } + public PVP2 getGeneralPVP2DBConfig() { return pvp2general; diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/entrypoints/DispatcherServlet.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/entrypoints/DispatcherServlet.java index 234641b4a..7130089ae 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/entrypoints/DispatcherServlet.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/entrypoints/DispatcherServlet.java @@ -69,7 +69,6 @@ public class DispatcherServlet extends AuthServlet{ protected void processRequest(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - boolean isValidSSOSession = false; boolean useSSOOA = false; String protocolRequestID = null; @@ -350,6 +349,7 @@ public class DispatcherServlet extends AuthServlet{ isValidSSOSession = ssomanager.isValidSSOSession(ssoId, req); useSSOOA = oaParam.useSSO(); + //if a legacy request is used SSO should not be allowed, actually boolean isUseMandateRequested = LegacyHelper.isUseMandateRequested(req); diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/ModulStorage.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/ModulStorage.java index 2a92f3ce5..31bf1ff58 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/ModulStorage.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/ModulStorage.java @@ -10,7 +10,8 @@ public class ModulStorage { private static final String[] modulClasses = new String[]{ "at.gv.egovernment.moa.id.protocols.saml1.SAML1Protocol", - "at.gv.egovernment.moa.id.protocols.pvp2x.PVP2XProtocol" + "at.gv.egovernment.moa.id.protocols.pvp2x.PVP2XProtocol", + "at.gv.egovernment.moa.id.protocols.oauth20.OAuth20Protocol" }; diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/OAuth20AuthAction.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/OAuth20AuthAction.java new file mode 100644 index 000000000..949b06bb2 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/OAuth20AuthAction.java @@ -0,0 +1,92 @@ +package at.gv.egovernment.moa.id.protocols.oauth20; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import at.gv.egovernment.moa.id.auth.data.AuthenticationSession; +import at.gv.egovernment.moa.id.auth.exception.MOAIDException; +import at.gv.egovernment.moa.id.commons.db.ex.MOADatabaseException; +import at.gv.egovernment.moa.id.moduls.IAction; +import at.gv.egovernment.moa.id.moduls.IRequest; +import at.gv.egovernment.moa.id.protocols.oauth20.exceptions.OAuth20ResponseTypeException; +import at.gv.egovernment.moa.id.protocols.oauth20.exceptions.OAuth20ServerErrorException; +import at.gv.egovernment.moa.id.protocols.oauth20.requests.OAuth20AuthRequest; +import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage; +import at.gv.egovernment.moa.logging.Logger; + +public class OAuth20AuthAction implements IAction { + + public String processRequest(IRequest req, HttpServletRequest httpReq, HttpServletResponse httpResp, + AuthenticationSession moasession) throws MOAIDException { + + OAuth20AuthRequest oAuthRequest = (OAuth20AuthRequest) req; + + // OAAuthParameter oaParam = + // AuthConfigurationProvider.getInstance().getOnlineApplicationParameter(oAuthRequest.getOAURL()); + // AuthenticationData authData = + // AuthenticationServer.buildAuthenticationData(moasession, oaParam, + // oAuthRequest.getTarget()); + + String responseType = oAuthRequest.getResponseType(); + + String code = AuthenticationSessionStoreage.changeSessionID(moasession); + Logger.debug("Stored session with id: " + code); + if (responseType.equals(OAuth20Constants.RESPONSE_CODE)) { + OAuth20SessionObject o = new OAuth20SessionObject(); + o.setScope(oAuthRequest.getScope()); + o.setCode(code); + moasession.setoAuth20SessionObject(o); + try { + AuthenticationSessionStoreage.storeSession(moasession); + } + catch (MOADatabaseException e) { + throw new OAuth20ServerErrorException(); + } + + Logger.debug("Saved OAuth20SessionObject in session with id: " + moasession.getSessionID()); + } else if (responseType.equals(OAuth20Constants.RESPONSE_TOKEN)) { + throw new OAuth20ResponseTypeException(); + } + + // add code and state to redirect url + httpResp.setStatus(HttpServletResponse.SC_FOUND); + String redirectURI = oAuthRequest.getRedirectUri(); + String state = oAuthRequest.getState(); + + redirectURI = this.addURLParameter(redirectURI, OAuth20Constants.RESPONSE_CODE, code); + redirectURI = this.addURLParameter(redirectURI, OAuth20Constants.PARAM_STATE, state); + + String finalUrl = redirectURI; + httpResp.addHeader("Location", finalUrl); + Logger.debug("REDIRECT TO: " + finalUrl.toString()); + return null; + } + + /* + * (non-Javadoc) + * @see + * at.gv.egovernment.moa.id.moduls.IAction#needAuthentication(at.gv.egovernment.moa.id.moduls + * .IRequest, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) + */ + public boolean needAuthentication(IRequest req, HttpServletRequest httpReq, HttpServletResponse httpResp) { + return true; + } + + private String addURLParameter(String url, String name, String value) { + String param = name + "=" + value; + if (url.indexOf("?") < 0) { + return url + "?" + param; + } else { + return url + "&" + param; + } + } + + /* + * (non-Javadoc) + * @see at.gv.egovernment.moa.id.moduls.IAction#getDefaultActionName() + */ + public String getDefaultActionName() { + return OAuth20Protocol.AUTH_ACTION; + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/OAuth20Configuration.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/OAuth20Configuration.java new file mode 100644 index 000000000..54c285b96 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/OAuth20Configuration.java @@ -0,0 +1,51 @@ +package at.gv.egovernment.moa.id.protocols.oauth20; + +import java.util.Properties; + +import at.gv.egovernment.moa.id.config.ConfigurationException; +import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider; + +public class OAuth20Configuration { + + private static OAuth20Configuration instance; + + public static OAuth20Configuration getInstance() { + if (instance == null) { + instance = new OAuth20Configuration(); + } + return instance; + } + + public static final String JWT_KEYSTORE = "jwt.ks.file"; + public static final String JWT_KEYSTORE_PASSWORD = "jwt.ks.password"; + public static final String JWT_KEY_NAME = "jwt.ks.key.name"; + public static final String JWT_KEY_PASSWORD = "jwt.ks.key.password"; + + private Properties props; + + private OAuth20Configuration() { + try { + props = AuthConfigurationProvider.getInstance().getGeneralOAuth20ProperiesConfig(); + } + catch (ConfigurationException e) { + e.printStackTrace(); + } + } + + public String getJWTKeyStore() { + return props.getProperty(JWT_KEYSTORE); + } + + public String getJWTKeyStorePassword() { + return props.getProperty(JWT_KEYSTORE_PASSWORD); + } + + public String getJWTKeyName() { + return props.getProperty(JWT_KEY_NAME); + } + + public String getJWTKeyPassword() { + return props.getProperty(JWT_KEY_PASSWORD); + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/OAuth20Constants.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/OAuth20Constants.java new file mode 100644 index 000000000..8189aa01b --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/OAuth20Constants.java @@ -0,0 +1,45 @@ +package at.gv.egovernment.moa.id.protocols.oauth20; + +public class OAuth20Constants { + + private OAuth20Constants() { + + } + + // error parameters and error codes + public static final String PARAM_ERROR = "error"; + public static final String PARAM_ERROR_DESCRIPTION = "error_description"; + public static final String PARAM_ERROR_URI = "error_uri"; + + public static final String ERROR_INVALID_REQUEST = "invalid_request"; + public static final String ERROR_UNSUPPORTED_RESPONSE_TYPE = "unsupported_response_type"; + public static final String ERROR_INVALID_CLIENT = "invalid_client"; + public static final String ERROR_ACCESS_DENIED = "access_denied"; + public static final String ERROR_SERVER_ERROR = "server_error"; + public static final String ERROR_INVALID_GRANT = "invalid_grant"; + public static final String ERROR_UNAUTHORIZED_CLIENT = "unauthorized_client"; + + // request parameters + //public static final String PARAM_OA_URL = "oaURL"; + public static final String PARAM_RESPONSE_TYPE = "response_type"; + public static final String PARAM_REDIRECT_URI = "redirect_uri"; + public static final String PARAM_STATE = "state"; + public static final String PARAM_GRANT_TYPE = "grant_type"; + public static final String PARAM_GRANT_TYPE_VALUE_AUTHORIZATION_CODE = "authorization_code"; + public static final String PARAM_CLIENT_ID = "client_id"; + public static final String PARAM_CLIENT_SECRET = "client_secret"; + public static final String PARAM_SCOPE = "scope"; + public static final String PARAM_MOA_MOD = "mod"; + public static final String PARAM_MOA_ACTION = "action"; + + + // reponse parameters + public static final String RESPONSE_CODE = "code"; + public static final String RESPONSE_TOKEN = "token"; + public static final String RESPONSE_ACCESS_TOKEN = "access_token"; + public static final String RESPONSE_ID_TOKEN = "id_token"; + public static final String RESPONSE_EXPIRES_IN = "expires_in"; + public static final String RESPONSE_TOKEN_TYPE = "token_type"; + public static final String RESPONSE_TOKEN_TYPE_VALUE_BEARER = "Bearer"; + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/OAuth20Protocol.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/OAuth20Protocol.java new file mode 100644 index 000000000..2c8aa8a73 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/OAuth20Protocol.java @@ -0,0 +1,166 @@ +package at.gv.egovernment.moa.id.protocols.oauth20; + +import java.net.URLEncoder; +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang.StringUtils; + +import at.gv.egovernment.moa.id.auth.exception.MOAIDException; +import at.gv.egovernment.moa.id.moduls.IAction; +import at.gv.egovernment.moa.id.moduls.IModulInfo; +import at.gv.egovernment.moa.id.moduls.IRequest; +import at.gv.egovernment.moa.id.protocols.oauth20.exceptions.OAuth20Exception; +import at.gv.egovernment.moa.id.protocols.oauth20.requests.OAuth20BaseRequest; +import at.gv.egovernment.moa.logging.Logger; + +import com.google.gson.JsonObject; + +public class OAuth20Protocol implements IModulInfo { + + public static final String NAME = OAuth20Protocol.class.getName(); + public static final String PATH = "id_oauth20"; + + public static final String AUTH_ACTION = "AUTH"; + public static final String TOKEN_ACTION = "TOKEN"; + + private static HashMap actions = new HashMap(); + + static { + actions.put(AUTH_ACTION, new OAuth20AuthAction()); + actions.put(TOKEN_ACTION, new OAuth20TokenAction()); + } + + public String getName() { + return NAME; + } + + public String getPath() { + return PATH; + } + + public IAction getAction(String action) { + return actions.get(action); + } + + /* + * (non-Javadoc) + * @see + * at.gv.egovernment.moa.id.moduls.IModulInfo#preProcess(javax.servlet.http.HttpServletRequest, + * javax.servlet.http.HttpServletResponse, java.lang.String) + */ + public IRequest preProcess(HttpServletRequest request, HttpServletResponse resp, String action) throws MOAIDException { + // validation is done inside creation + OAuth20BaseRequest res = OAuth20BaseRequest.newInstance(action, request); + Logger.debug("Created: " + res); + return res; + } + + /* + * (non-Javadoc) + * @see + * at.gv.egovernment.moa.id.moduls.IModulInfo#canHandleRequest(javax.servlet.http.HttpServletRequest + * , javax.servlet.http.HttpServletResponse) + */ + public IAction canHandleRequest(HttpServletRequest request, HttpServletResponse response) { + if (request.getParameter("action").equals(AUTH_ACTION)) { + return getAction(AUTH_ACTION); + } else if (request.getParameter("action").equals(TOKEN_ACTION)) { + return getAction(TOKEN_ACTION); + } + + return null;// getAction(AUTH_ACTION); + } + + /* + * (non-Javadoc) + * @see at.gv.egovernment.moa.id.moduls.IModulInfo#generateErrorMessage(java.lang.Throwable, + * javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, + * at.gv.egovernment.moa.id.moduls.IRequest) + */ + public boolean generateErrorMessage(Throwable e, HttpServletRequest request, HttpServletResponse response, IRequest protocolRequest) + throws Throwable { + + StringBuilder url = new StringBuilder(); + + String paramRedirect = request.getParameter(OAuth20Constants.PARAM_REDIRECT_URI); + + if (e instanceof OAuth20Exception) { + + String action = request.getParameter("action"); + + Logger.debug("Going to throw O OAuth20Exception for action: " + action); + OAuth20Exception oAuth20Exception = ((OAuth20Exception) e); + + String errorCode = oAuth20Exception.getErrorCode(); + String errorDescription = oAuth20Exception.getMessage(); + // String errorUri = "http://tools.ietf.org/html/draft-ietf-oauth-v2-11"; + + if (action.equals(AUTH_ACTION)) { + + // check if given redirect url is ok + if (StringUtils.isNotEmpty(paramRedirect) && OAuth20Util.isUrl(paramRedirect)) { + url.append(paramRedirect); + + // otherwise throw an + } else { + throw new MOAIDException("oauth20.01", new Object[] {}); + } + + String state = request.getParameter(OAuth20Constants.PARAM_STATE); + + OAuth20Util.addParameterToURL(url, OAuth20Constants.PARAM_ERROR, errorCode); + OAuth20Util.addParameterToURL(url, OAuth20Constants.PARAM_ERROR_DESCRIPTION, + URLEncoder.encode(oAuth20Exception.getMessageId() + ": " + errorDescription, "UTF-8")); + // OAuth20Util.addParameterToURL(url, OAuth20Constants.PARAM_ERROR_URI, errorUri); + OAuth20Util.addParameterToURL(url, OAuth20Constants.PARAM_STATE, state); + + response.setContentType("text/html"); + response.setStatus(HttpServletResponse.SC_FOUND); + response.addHeader("Location", url.toString()); + Logger.debug("REDIRECT TO: " + url.toString()); + return true; + + } else if (action.equals(TOKEN_ACTION)) { + Map params = new HashMap(); + params.put(OAuth20Constants.PARAM_ERROR, errorCode); + params.put(OAuth20Constants.PARAM_ERROR_DESCRIPTION, + URLEncoder.encode(oAuth20Exception.getMessageId() + ": " + errorDescription, "UTF-8")); + // params.put(OAuth20Constants.PARAM_ERROR_URI, errorUri); + + // create response + JsonObject jsonObject = new JsonObject(); + OAuth20Util.addProperytiesToJsonObject(jsonObject, params); + String jsonResponse = jsonObject.toString(); + Logger.debug("JSON Response: " + jsonResponse); + + // write respone to http response + response.setContentType("application/json"); + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + response.getOutputStream().print(jsonResponse); + response.getOutputStream().close(); + + return true; + } + + } + + return false; + + } + + /* + * (non-Javadoc) + * @see + * at.gv.egovernment.moa.id.moduls.IModulInfo#validate(javax.servlet.http.HttpServletRequest, + * javax.servlet.http.HttpServletResponse, at.gv.egovernment.moa.id.moduls.IRequest) + */ + public boolean validate(HttpServletRequest request, HttpServletResponse response, IRequest pending) { + // we validate in the preProcess + return true; + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/OAuth20SessionObject.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/OAuth20SessionObject.java new file mode 100644 index 000000000..91c099d2c --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/OAuth20SessionObject.java @@ -0,0 +1,39 @@ +package at.gv.egovernment.moa.id.protocols.oauth20; + +import java.io.Serializable; + +public class OAuth20SessionObject implements Serializable { + + /** + * + */ + private static final long serialVersionUID = 1L; + + private String scope; + + private String code; + + public String getScope() { + return scope; + } + + public void setScope(String scope) { + this.scope = scope; + } + + /** + * @return the code + */ + public String getCode() { + return code; + } + + /** + * @param code + * the code to set + */ + public void setCode(String code) { + this.code = code; + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/OAuth20TokenAction.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/OAuth20TokenAction.java new file mode 100644 index 000000000..70f425148 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/OAuth20TokenAction.java @@ -0,0 +1,346 @@ +package at.gv.egovernment.moa.id.protocols.oauth20; + +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.UUID; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import net.oauth.jsontoken.JsonToken; +import net.oauth.jsontoken.crypto.Signer; + +import org.w3c.dom.Element; + +import at.gv.e_government.reference.namespace.mandates._20040701_.Mandate; +import at.gv.e_government.reference.namespace.persondata._20020228_.CorporateBodyType; +import at.gv.e_government.reference.namespace.persondata._20020228_.IdentificationType; +import at.gv.e_government.reference.namespace.persondata._20020228_.PersonNameType.FamilyName; +import at.gv.e_government.reference.namespace.persondata._20020228_.PhysicalPersonType; +import at.gv.egovernment.moa.id.auth.AuthenticationServer; +import at.gv.egovernment.moa.id.auth.builder.BPKBuilder; +import at.gv.egovernment.moa.id.auth.data.AuthenticationSession; +import at.gv.egovernment.moa.id.auth.exception.BuildException; +import at.gv.egovernment.moa.id.auth.exception.MOAIDException; +import at.gv.egovernment.moa.id.commons.db.ex.MOADatabaseException; +import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider; +import at.gv.egovernment.moa.id.config.auth.OAAuthParameter; +import at.gv.egovernment.moa.id.data.AuthenticationData; +import at.gv.egovernment.moa.id.moduls.IAction; +import at.gv.egovernment.moa.id.moduls.IRequest; +import at.gv.egovernment.moa.id.protocols.oauth20.exceptions.OAuth20ServerErrorException; +import at.gv.egovernment.moa.id.protocols.oauth20.exceptions.OAuth20UnauthorizedClientException; +import at.gv.egovernment.moa.id.protocols.oauth20.requests.OAuth20TokenRequest; +import at.gv.egovernment.moa.id.protocols.pvp2x.PVPConstants; +import at.gv.egovernment.moa.id.protocols.pvp2x.utils.AttributeExtractor; +import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage; +import at.gv.egovernment.moa.id.util.IdentityLinkReSigner; +import at.gv.egovernment.moa.id.util.MandateBuilder; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.Base64Utils; +import at.gv.egovernment.moa.util.Constants; +import at.gv.egovernment.moa.util.DOMUtils; + +import com.google.gson.JsonObject; + +public class OAuth20TokenAction implements IAction { + + private int expirationTime = 5 * 60; // in seconds + + public class Pair { + private T1 first; + private T2 second; + + public Pair(T1 newFirst, T2 newSecond) { + first = newFirst; + second = newSecond; + } + + public T1 getFirst() { + return first; + } + + public T2 getSecond() { + return second; + } + } + + public String processRequest(IRequest req, HttpServletRequest httpReq, HttpServletResponse httpResp, + AuthenticationSession moasession) throws MOAIDException { + + AuthenticationSession session = null; + try { + OAuth20TokenRequest oAuthRequest = (OAuth20TokenRequest) req; + + session = AuthenticationSessionStoreage.getSession(oAuthRequest.getCode()); + if (session == null) { + throw new OAuth20UnauthorizedClientException(); + } + + OAuth20SessionObject auth20SessionObject = session.getoAuth20SessionObject(); + Logger.debug("Loaded OAuth20SessionObject from session: " + auth20SessionObject); + + // do checking for different grant types and code + if (!auth20SessionObject.getCode().equals(oAuthRequest.getCode())) { + throw new OAuth20UnauthorizedClientException(); + + } + + final String accessToken = UUID.randomUUID().toString(); + + // create response + Map params = new HashMap(); + params.put(OAuth20Constants.RESPONSE_ACCESS_TOKEN, accessToken); + params.put(OAuth20Constants.RESPONSE_TOKEN_TYPE, OAuth20Constants.RESPONSE_TOKEN_TYPE_VALUE_BEARER); + params.put(OAuth20Constants.RESPONSE_EXPIRES_IN, this.expirationTime); + + // build id token and scope + Pair pair = buildIdToken(auth20SessionObject.getScope(), oAuthRequest, session); + Logger.debug("RESPONSE ID_TOKEN: " + pair.getFirst()); + params.put(OAuth20Constants.RESPONSE_ID_TOKEN, pair.getFirst()); + Logger.debug("RESPONSE SCOPE: " + pair.getSecond()); + params.put(OAuth20Constants.PARAM_SCOPE, pair.getSecond()); + + // create response + JsonObject jsonObject = new JsonObject(); + OAuth20Util.addProperytiesToJsonObject(jsonObject, params); + String jsonResponse = jsonObject.toString(); + Logger.debug("JSON Response: " + jsonResponse); + + // write respone to http response + httpResp.setContentType("application/json"); + httpResp.setStatus(HttpServletResponse.SC_OK); + httpResp.getOutputStream().print(jsonResponse); + httpResp.getOutputStream().close(); + + return null; + } + catch (Exception e) { + throw new OAuth20ServerErrorException(); + } + finally { + if (session != null) { + // destroy session for clean up + try { + Logger.debug("Going to destroy session: " + session.getSessionID()); + AuthenticationSessionStoreage.destroySession(session.getSessionID()); + } + catch (MOADatabaseException e) { + } + } + } + } + + /* + * (non-Javadoc) + * @see + * at.gv.egovernment.moa.id.moduls.IAction#needAuthentication(at.gv.egovernment.moa.id.moduls + * .IRequest, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) + */ + public boolean needAuthentication(IRequest req, HttpServletRequest httpReq, HttpServletResponse httpResp) { + return false; + } + + /* + * (non-Javadoc) + * @see at.gv.egovernment.moa.id.moduls.IAction#getDefaultActionName() + */ + public String getDefaultActionName() { + return OAuth20Protocol.TOKEN_ACTION; + } + + private Pair buildIdToken(String scope, OAuth20TokenRequest oAuthRequest, AuthenticationSession session) + throws Exception { + OAAuthParameter oaParam = AuthConfigurationProvider.getInstance().getOnlineApplicationParameter(oAuthRequest.getOAURL()); + AuthenticationData authData = AuthenticationServer.buildAuthenticationData(session, oaParam, oAuthRequest.getTarget()); + + Map params = new HashMap(); + StringBuilder resultScopes = new StringBuilder(); + // always fill with open id + this.fillScopeOpenId(params, authData); + resultScopes.append("openId"); + + for (String s : scope.split(" ")) { + + try { + if (s.equalsIgnoreCase("profile")) { + this.fillScopeProfile(params, authData); + resultScopes.append(" profile"); + } else if (s.equalsIgnoreCase("eID")) { + this.fillScopeEID(params, authData, session); + resultScopes.append(" eID"); + } else if (s.equalsIgnoreCase("eID_gov") && oaParam.getBusinessService()) { + this.fillScopeEID_GOV(params, authData, session); + resultScopes.append(" eID_gov"); + } else if (s.equalsIgnoreCase("mandate") && session.getUseMandate() && oaParam.getBusinessService()) { + this.fillScopeMandate(params, oaParam, authData, session); + resultScopes.append(" mandate"); + } + } + catch (Exception e) { + Logger.warn(e.getMessage(), e); + } + // TODO parser STORK + } + + // add properties and sign + // HmacSHA256Signer signer = new HmacSHA256Signer("testSigner", "key_id", + // "super_secure_pwd".getBytes()); + // Signer signer = OAuth20Util.loadSigner(authData.getIssuer(), oaParam.getoAuth20Config()); + Signer signer = OAuth20Util.loadSigner(authData.getIssuer()); + JsonToken token = new JsonToken(signer); + OAuth20Util.addProperytiesToJsonObject(token.getPayloadAsJsonObject(), params); + return new Pair(token.serializeAndSign(), resultScopes.toString()); + } + + private void fillScopeProfile(Map params, AuthenticationData authData) { + params.put("given_name", authData.getGivenName()); + params.put("family_name", authData.getFamilyName()); + params.put("birthdate", authData.getDateOfBirth()); + } + + private void fillScopeOpenId(Map params, AuthenticationData authData) { + params.put("iss", authData.getIssuer()); + params.put("sub", authData.getBPK()); + // params.put("aud", ""); // not used + params.put("exp", (long) (new Date().getTime() / 1000 + this.expirationTime)); + params.put("iat", (long) (new Date().getTime() / 1000)); + params.put("auth_time", (long) (authData.getTimestamp().getTime() / 1000)); + // params.put("acr", ""); //? + } + + private void fillScopeEID(Map params, AuthenticationData authData, AuthenticationSession session) throws Exception { + params.put(PVPConstants.EID_CCS_URL_FRIENDLY_NAME, authData.getBkuURL()); + // params.put("ENC-BPK-LIST", ); // not used + // params.put("MAIL", ); //not used + // params.put("TEL", ); //not used + + params.put(PVPConstants.EID_CITIZEN_QAA_LEVEL_FRIENDLY_NAME, 4); + params.put(PVPConstants.EID_ISSUING_NATION_FRIENDLY_NAME, "AT"); + params.put(PVPConstants.EID_SECTOR_FOR_IDENTIFIER_FRIENDLY_NAME, authData.getBPKType()); + params.put(PVPConstants.EID_AUTH_BLOCK_FRIENDLY_NAME, Base64Utils.encode(session.getAuthBlock().getBytes())); + params.put(PVPConstants.EID_SIGNER_CERTIFICATE_FRIENDLY_NAME, Base64Utils.encode(session.getEncodedSignerCertificate())); + // params.put(PVPConstants.EID_STORK_TOKEN_FRIENDLY_NAME, ); //not used + + // bpk + String bpk = authData.getBPK(); + String type = authData.getBPKType(); + if (type.startsWith(Constants.URN_PREFIX_WBPK)) + type = type.substring((Constants.URN_PREFIX_WBPK + "+").length()); + else if (type.startsWith(Constants.URN_PREFIX_CDID)) type = type.substring((Constants.URN_PREFIX_CDID + "+").length()); + if (bpk.length() > PVPConstants.BPK_MAX_LENGTH) { + bpk = bpk.substring(0, PVPConstants.BPK_MAX_LENGTH); + } + params.put(PVPConstants.BPK_FRIENDLY_NAME, type + ":" + bpk); + } + + private void fillScopeEID_GOV(Map params, AuthenticationData authData, AuthenticationSession session) + throws Exception { + params.put(PVPConstants.EID_SOURCE_PIN_FRIENDLY_NAME, authData.getIdentificationValue()); + params.put(PVPConstants.EID_SOURCE_PIN_TYPE_FRIENDLY_NAME, authData.getIdentificationType()); + + IdentityLinkReSigner identitylinkresigner = IdentityLinkReSigner.getInstance(); + Element resignedilAssertion = identitylinkresigner.resignIdentityLink(authData.getIdentityLink().getSamlAssertion()); + params.put(PVPConstants.EID_IDENTITY_LINK_FRIENDLY_NAME, + Base64Utils.encode(DOMUtils.serializeNode(resignedilAssertion).getBytes())); + } + + private void fillScopeMandate(Map params, OAAuthParameter oaParam, AuthenticationData authData, + AuthenticationSession session) { + Element mandate = session.getMandate(); + + if (mandate == null) { + throw new OAuth20ServerErrorException(); + } + Mandate mandateObject = MandateBuilder.buildMandate(mandate); + if (mandateObject == null) { + throw new OAuth20ServerErrorException(); + } + + params.put(PVPConstants.MANDATE_TYPE_FRIENDLY_NAME, mandateObject.getAnnotation()); + params.put(PVPConstants.MANDATE_REFERENCE_VALUE_FRIENDLY_NAME, mandateObject.getMandateID()); + + // natural person + PhysicalPersonType physicalPerson = mandateObject.getMandator().getPhysicalPerson(); + if (physicalPerson != null && physicalPerson.getIdentification().size() != 0) { + IdentificationType id = physicalPerson.getIdentification().get(0); + params.put(PVPConstants.MANDATE_NAT_PER_SOURCE_PIN_FRIENDLY_NAME, id.getValue().getValue()); + params.put(PVPConstants.MANDATE_NAT_PER_SOURCE_PIN_TYPE_FRIENDLY_NAME, id.getType()); + + try { + String bpk; + if (id.getType().equals(Constants.URN_PREFIX_BASEID)) { + if (session.getBusinessService()) { + bpk = new BPKBuilder().buildWBPK(id.getValue().getValue(), oaParam.getIdentityLinkDomainIdentifier()); + } else { + bpk = new BPKBuilder().buildBPK(id.getValue().getValue(), oaParam.getTarget()); + } + } else { + bpk = id.getValue().getValue(); + } + params.put(PVPConstants.MANDATE_NAT_PER_BPK_FRIENDLY_NAME, bpk); + } + catch (BuildException e) { + // ignore + } + + // params.put(PVPConstants.MANDATE_NAT_PER_ENC_BPK_LIST_FRIENDLY_NAME, ); //not used + + StringBuilder sb = new StringBuilder(); + Iterator fNamesit = physicalPerson.getName().getFamilyName().iterator(); + + while (fNamesit.hasNext()) { + sb.append(" " + fNamesit.next().getValue()); + } + params.put(PVPConstants.MANDATE_NAT_PER_FAMILY_NAME_FRIENDLY_NAME, sb.toString()); + + sb = new StringBuilder(); + Iterator gNamesit = physicalPerson.getName().getGivenName().iterator(); + + while (gNamesit.hasNext()) { + sb.append(" " + gNamesit.next()); + } + params.put(PVPConstants.MANDATE_NAT_PER_GIVEN_NAME_FRIENDLY_NAME, sb.toString()); + + try { + DateFormat mandateFormat = new SimpleDateFormat(MandateBuilder.MANDATE_DATE_OF_BIRTH_FORMAT); + Date date = mandateFormat.parse(physicalPerson.getDateOfBirth()); + DateFormat pvpDateFormat = new SimpleDateFormat(PVPConstants.MANDATE_NAT_PER_BIRTHDATE_FORMAT_PATTERN); + String dateString = pvpDateFormat.format(date); + params.put(PVPConstants.MANDATE_NAT_PER_BIRTHDATE_FRIENDLY_NAME, dateString); + } + catch (ParseException e) { + // ignore + } + + } + + // legal person + CorporateBodyType corporation = mandateObject.getMandator().getCorporateBody(); + if (corporation != null && corporation.getIdentification().size() != 0) { + IdentificationType id = corporation.getIdentification().get(0); + params.put(PVPConstants.MANDATE_LEG_PER_SOURCE_PIN_FRIENDLY_NAME, id.getValue().getValue()); + params.put(PVPConstants.MANDATE_LEG_PER_SOURCE_PIN_TYPE_FRIENDLY_NAME, id.getType()); + params.put(PVPConstants.MANDATE_LEG_PER_FULL_NAME_FRIENDLY_NAME, corporation.getFullName()); + } + + String oid = AttributeExtractor.extractSAMLAttributeOA(EXT_SAML_MANDATE_OID, session); + if (oid != null) { + params.put(PVPConstants.MANDATE_PROF_REP_OID_FRIENDLY_NAME, oid); + } + + String text = AttributeExtractor.extractSAMLAttributeOA(EXT_SAML_MANDATE_OIDTEXTUALDESCRIPTION, session); + + if (text != null) { + params.put(PVPConstants.MANDATE_PROF_REP_DESC_FRIENDLY_NAME, oid); + } + + // params.put("MANDATE-FULL-MANDATE-LIST", ); // not used + + } +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/OAuth20Util.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/OAuth20Util.java new file mode 100644 index 000000000..4d3030a0f --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/OAuth20Util.java @@ -0,0 +1,134 @@ +package at.gv.egovernment.moa.id.protocols.oauth20; + +import java.io.UnsupportedEncodingException; +import java.security.KeyStore; +import java.security.PrivateKey; +import java.security.cert.X509Certificate; +import java.security.interfaces.RSAPrivateKey; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import net.oauth.jsontoken.crypto.RsaSHA256Signer; +import net.oauth.jsontoken.crypto.Signer; + +import org.opensaml.xml.security.x509.BasicX509Credential; + +import at.gv.egovernment.moa.id.commons.db.dao.config.OAOAUTH20; +import at.gv.egovernment.moa.id.protocols.oauth20.exceptions.OAuth20CertificateErrorException; +import at.gv.egovernment.moa.id.protocols.oauth20.exceptions.OAuth20Exception; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.KeyStoreUtils; +import at.gv.egovernment.moa.util.StringUtils; + +import com.google.gson.JsonObject; + +public class OAuth20Util { + + public static final String REGEX_HTTPS = "^(https?)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]"; + public static final String REGEX_FILE = "^(file):/.[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]"; + + /** + * Simple helper function to add parameter to a url + * + * @param url + * @param name + * @param value + * @throws UnsupportedEncodingException + */ + public static void addParameterToURL(final StringBuilder url, final String name, final String value) + throws UnsupportedEncodingException { + if (url.indexOf("?") < 0) { + url.append("?"); + } else { + url.append("&"); + } + // URLEncoder.encode(value, "UTF-8") + url.append(name).append("=").append(value); + } + + public static boolean isUrl(final String url) { + Pattern urlPattern; + if (url.startsWith("file")) { + urlPattern = Pattern.compile(REGEX_FILE, Pattern.CASE_INSENSITIVE); + } else { + urlPattern = Pattern.compile(REGEX_HTTPS, Pattern.CASE_INSENSITIVE); + } + + Matcher matcher = urlPattern.matcher(url); + return matcher.find(); + } + + public static void addProperytiesToJsonObject(JsonObject jsonObject, Map params) { + for (Map.Entry param : params.entrySet()) { + if (param.getKey() != null && !"".equals(param.getKey()) && param.getValue() != null && !"".equals(param.getValue())) { + + // check for integer + try { + int i = Integer.parseInt(String.valueOf(param.getValue())); + jsonObject.addProperty(param.getKey(), i); + continue; + } + catch (NumberFormatException e) { + } + + // check for long + try { + long l = Long.parseLong(String.valueOf(param.getValue())); + jsonObject.addProperty(param.getKey(), l); + continue; + } + catch (NumberFormatException e) { + } + + // string + if (param.getValue() instanceof String) { + jsonObject.addProperty(param.getKey(), String.valueOf(param.getValue())); + } + } + } + } + + public static Signer loadSigner(String issuer) throws OAuth20Exception { + OAuth20Configuration globalConfig = OAuth20Configuration.getInstance(); + + if (StringUtils.isEmpty(globalConfig.getJWTKeyStore())) { + throw new OAuth20CertificateErrorException("keystore"); + } + + if (StringUtils.isEmpty(globalConfig.getJWTKeyName())) { + throw new OAuth20CertificateErrorException("key name"); + } + + try { + KeyStore ks = KeyStoreUtils.loadKeyStore(globalConfig.getJWTKeyStore(), globalConfig.getJWTKeyStorePassword()); + + X509Certificate certificate = (X509Certificate) ks.getCertificate(globalConfig.getJWTKeyName()); + + PrivateKey privateKey = (PrivateKey) ks.getKey(globalConfig.getJWTKeyName(), globalConfig.getJWTKeyPassword() + .toCharArray()); + BasicX509Credential credential = new BasicX509Credential(); + credential.setEntityCertificate(certificate); + credential.setPrivateKey(privateKey); + + //Logger.debug("Going to use X509Certificate:"); + Logger.debug(certificate); + //Logger.debug("Going to use private key:"); + Logger.debug(privateKey); + + return new RsaSHA256Signer(issuer, globalConfig.getJWTKeyName(), (RSAPrivateKey) credential.getPrivateKey()); + + } + catch (Exception e) { + throw new OAuth20CertificateErrorException("keystore"); + } + + } + + public static boolean isValidStateValue(String state) { + Pattern urlPattern = Pattern.compile("javascript|<|>|&|;", Pattern.CASE_INSENSITIVE); + Matcher matcher = urlPattern.matcher(state); + return !matcher.find(); + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/exceptions/OAuth20AccessDeniedException.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/exceptions/OAuth20AccessDeniedException.java new file mode 100644 index 000000000..e4abd5bd1 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/exceptions/OAuth20AccessDeniedException.java @@ -0,0 +1,12 @@ +package at.gv.egovernment.moa.id.protocols.oauth20.exceptions; + +import at.gv.egovernment.moa.id.protocols.oauth20.OAuth20Constants; + +public class OAuth20AccessDeniedException extends OAuth20Exception { + private static final long serialVersionUID = 1L; + + public OAuth20AccessDeniedException() { + super(OAuth20Constants.ERROR_ACCESS_DENIED, "oauth20.05", new Object[] {}); + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/exceptions/OAuth20CertificateErrorException.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/exceptions/OAuth20CertificateErrorException.java new file mode 100644 index 000000000..6f5a41ca5 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/exceptions/OAuth20CertificateErrorException.java @@ -0,0 +1,12 @@ +package at.gv.egovernment.moa.id.protocols.oauth20.exceptions; + +import at.gv.egovernment.moa.id.protocols.oauth20.OAuth20Constants; + +public class OAuth20CertificateErrorException extends OAuth20Exception { + private static final long serialVersionUID = 1L; + + public OAuth20CertificateErrorException(final String name) { + super(OAuth20Constants.ERROR_SERVER_ERROR, "oauth20.09", new Object[] { name }); + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/exceptions/OAuth20Exception.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/exceptions/OAuth20Exception.java new file mode 100644 index 000000000..1c4cb20ac --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/exceptions/OAuth20Exception.java @@ -0,0 +1,49 @@ +package at.gv.egovernment.moa.id.protocols.oauth20.exceptions; + +import at.gv.egovernment.moa.id.util.MOAIDMessageProvider; + +public class OAuth20Exception extends RuntimeException { + + private static final long serialVersionUID = 1L; + + private String messageId; + + private String errorCode; + + public OAuth20Exception(final String errorCode, final String messageId, final Object[] parameters) { + super(MOAIDMessageProvider.getInstance().getMessage(messageId, parameters)); + this.errorCode = errorCode; + this.messageId = messageId; + } + + /** + * @return the messageId + */ + public String getMessageId() { + return messageId; + } + + /** + * @param messageId + * the messageId to set + */ + public void setMessageId(String messageId) { + this.messageId = messageId; + } + + /** + * @return the errorCode + */ + public String getErrorCode() { + return errorCode; + } + + /** + * @param errorCode + * the errorCode to set + */ + public void setErrorCode(String errorCode) { + this.errorCode = errorCode; + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/exceptions/OAuth20InvalidClientException.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/exceptions/OAuth20InvalidClientException.java new file mode 100644 index 000000000..2a2ec4498 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/exceptions/OAuth20InvalidClientException.java @@ -0,0 +1,12 @@ +package at.gv.egovernment.moa.id.protocols.oauth20.exceptions; + +import at.gv.egovernment.moa.id.protocols.oauth20.OAuth20Constants; + +public class OAuth20InvalidClientException extends OAuth20Exception { + private static final long serialVersionUID = 1L; + + public OAuth20InvalidClientException() { + super(OAuth20Constants.ERROR_INVALID_CLIENT, "oauth20.05", new Object[] {}); + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/exceptions/OAuth20InvalidGrantException.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/exceptions/OAuth20InvalidGrantException.java new file mode 100644 index 000000000..288667104 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/exceptions/OAuth20InvalidGrantException.java @@ -0,0 +1,12 @@ +package at.gv.egovernment.moa.id.protocols.oauth20.exceptions; + +import at.gv.egovernment.moa.id.protocols.oauth20.OAuth20Constants; + +public class OAuth20InvalidGrantException extends OAuth20Exception { + private static final long serialVersionUID = 1L; + + public OAuth20InvalidGrantException() { + super(OAuth20Constants.ERROR_INVALID_GRANT, "oauth20.07", new Object[] {}); + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/exceptions/OAuth20InvalidRequestException.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/exceptions/OAuth20InvalidRequestException.java new file mode 100644 index 000000000..30c1cb1cc --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/exceptions/OAuth20InvalidRequestException.java @@ -0,0 +1,13 @@ +package at.gv.egovernment.moa.id.protocols.oauth20.exceptions; + +import at.gv.egovernment.moa.id.protocols.oauth20.OAuth20Constants; + +public class OAuth20InvalidRequestException extends OAuth20Exception { + private static final long serialVersionUID = 1L; + + public OAuth20InvalidRequestException() { + super(OAuth20Constants.ERROR_INVALID_REQUEST, "oauth20.04", new Object[] {}); + + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/exceptions/OAuth20ResponseTypeException.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/exceptions/OAuth20ResponseTypeException.java new file mode 100644 index 000000000..5dd0a13c3 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/exceptions/OAuth20ResponseTypeException.java @@ -0,0 +1,12 @@ +package at.gv.egovernment.moa.id.protocols.oauth20.exceptions; + +import at.gv.egovernment.moa.id.protocols.oauth20.OAuth20Constants; + +public class OAuth20ResponseTypeException extends OAuth20Exception { + private static final long serialVersionUID = 1L; + + public OAuth20ResponseTypeException() { + super(OAuth20Constants.ERROR_UNSUPPORTED_RESPONSE_TYPE, "oauth20.03", new Object[] {}); + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/exceptions/OAuth20ServerErrorException.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/exceptions/OAuth20ServerErrorException.java new file mode 100644 index 000000000..59855d511 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/exceptions/OAuth20ServerErrorException.java @@ -0,0 +1,12 @@ +package at.gv.egovernment.moa.id.protocols.oauth20.exceptions; + +import at.gv.egovernment.moa.id.protocols.oauth20.OAuth20Constants; + +public class OAuth20ServerErrorException extends OAuth20Exception { + private static final long serialVersionUID = 1L; + + public OAuth20ServerErrorException() { + super(OAuth20Constants.ERROR_SERVER_ERROR, "oauth20.06", new Object[] {}); + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/exceptions/OAuth20UnauthorizedClientException.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/exceptions/OAuth20UnauthorizedClientException.java new file mode 100644 index 000000000..28cc44968 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/exceptions/OAuth20UnauthorizedClientException.java @@ -0,0 +1,12 @@ +package at.gv.egovernment.moa.id.protocols.oauth20.exceptions; + +import at.gv.egovernment.moa.id.protocols.oauth20.OAuth20Constants; + +public class OAuth20UnauthorizedClientException extends OAuth20Exception { + private static final long serialVersionUID = 1L; + + public OAuth20UnauthorizedClientException() { + super(OAuth20Constants.ERROR_UNAUTHORIZED_CLIENT, "oauth20.08", new Object[] {}); + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/exceptions/OAuth20WrongParameterException.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/exceptions/OAuth20WrongParameterException.java new file mode 100644 index 000000000..24d151869 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/exceptions/OAuth20WrongParameterException.java @@ -0,0 +1,12 @@ +package at.gv.egovernment.moa.id.protocols.oauth20.exceptions; + +import at.gv.egovernment.moa.id.protocols.oauth20.OAuth20Constants; + +public class OAuth20WrongParameterException extends OAuth20Exception { + private static final long serialVersionUID = 1L; + + public OAuth20WrongParameterException(final String name) { + super(OAuth20Constants.ERROR_INVALID_REQUEST, "oauth20.02", new Object[] { name }); + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/requests/OAuth20AuthRequest.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/requests/OAuth20AuthRequest.java new file mode 100644 index 000000000..8aac75413 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/requests/OAuth20AuthRequest.java @@ -0,0 +1,134 @@ +package at.gv.egovernment.moa.id.protocols.oauth20.requests; + +import javax.servlet.http.HttpServletRequest; + +import at.gv.egovernment.moa.id.commons.db.dao.config.OAOAUTH20; +import at.gv.egovernment.moa.id.config.ConfigurationException; +import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider; +import at.gv.egovernment.moa.id.protocols.oauth20.OAuth20Constants; +import at.gv.egovernment.moa.id.protocols.oauth20.OAuth20Util; +import at.gv.egovernment.moa.id.protocols.oauth20.exceptions.OAuth20AccessDeniedException; +import at.gv.egovernment.moa.id.protocols.oauth20.exceptions.OAuth20Exception; +import at.gv.egovernment.moa.id.protocols.oauth20.exceptions.OAuth20ResponseTypeException; +import at.gv.egovernment.moa.id.protocols.oauth20.exceptions.OAuth20WrongParameterException; + +public class OAuth20AuthRequest extends OAuth20BaseRequest { + + private static final long serialVersionUID = 1L; + + private String responseType; + private String state; + private String redirectUri; + private String scope; + private String clientID; + + /** + * @return the responseType + */ + public String getResponseType() { + return responseType; + } + + /** + * @param responseType + * the responseType to set + */ + public void setResponseType(String responseType) { + this.responseType = responseType; + } + + /** + * @return the state + */ + public String getState() { + return state; + } + + /** + * @param state + * the state to set + */ + public void setState(String state) { + this.state = state; + } + + /** + * @return the redirectUri + */ + public String getRedirectUri() { + return redirectUri; + } + + /** + * @param redirectUri + * the redirectUri to set + */ + public void setRedirectUri(String redirectUri) { + this.redirectUri = redirectUri; + } + + /** + * @return the scope + */ + public String getScope() { + return scope; + } + + /** + * @param scope + * the scope to set + */ + public void setScope(String scope) { + this.scope = scope; + } + + /** + * @return the clientID + */ + public String getClientID() { + return clientID; + } + + /** + * @param clientID + * the clientID to set + */ + public void setClientID(String clientID) { + this.clientID = clientID; + } + + @Override + protected void populateSpecialParameters(HttpServletRequest request) throws OAuth20Exception { + this.setResponseType(this.getParam(request, OAuth20Constants.PARAM_RESPONSE_TYPE, true)); + this.setState(this.getParam(request, OAuth20Constants.PARAM_STATE, true)); + this.setRedirectUri(this.getParam(request, OAuth20Constants.PARAM_REDIRECT_URI, true)); + this.setClientID(this.getParam(request, OAuth20Constants.PARAM_CLIENT_ID, true)); + this.setScope(this.getParam(request, OAuth20Constants.PARAM_SCOPE, false)); + + // check for response type + if (!this.responseType.equals(OAuth20Constants.RESPONSE_CODE)) { + throw new OAuth20ResponseTypeException(); + } + + // check state for invalid characters (like < > & ; ... javascript ... to prevent xss) + if (!OAuth20Util.isValidStateValue(this.getState())) { + throw new OAuth20WrongParameterException(OAuth20Constants.PARAM_STATE); + } + + // check if client id and redirect uri are ok + try { + // OAOAUTH20 cannot be null at this point. check was done in base request + OAOAUTH20 oAuthConfig = AuthConfigurationProvider.getInstance().getOnlineApplicationParameter(this.getOAURL()) + .getoAuth20Config(); + + if (!this.getClientID().equals(oAuthConfig.getOAuthClientId()) + || !this.getRedirectUri().equals(oAuthConfig.getOAuthRedirectUri())) { + throw new OAuth20AccessDeniedException(); + } + } + catch (ConfigurationException e) { + throw new OAuth20WrongParameterException(OAuth20Constants.PARAM_CLIENT_ID); + } + + } +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/requests/OAuth20BaseRequest.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/requests/OAuth20BaseRequest.java new file mode 100644 index 000000000..05362c977 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/requests/OAuth20BaseRequest.java @@ -0,0 +1,118 @@ +package at.gv.egovernment.moa.id.protocols.oauth20.requests; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.lang.StringEscapeUtils; +import org.apache.commons.lang.StringUtils; + +import at.gv.egovernment.moa.id.commons.db.dao.config.OAOAUTH20; +import at.gv.egovernment.moa.id.config.ConfigurationException; +import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider; +import at.gv.egovernment.moa.id.config.auth.OAAuthParameter; +import at.gv.egovernment.moa.id.moduls.RequestImpl; +import at.gv.egovernment.moa.id.protocols.oauth20.OAuth20Constants; +import at.gv.egovernment.moa.id.protocols.oauth20.OAuth20Protocol; +import at.gv.egovernment.moa.id.protocols.oauth20.exceptions.OAuth20Exception; +import at.gv.egovernment.moa.id.protocols.oauth20.exceptions.OAuth20InvalidRequestException; +import at.gv.egovernment.moa.id.protocols.oauth20.exceptions.OAuth20ServerErrorException; +import at.gv.egovernment.moa.id.protocols.oauth20.exceptions.OAuth20WrongParameterException; +import at.gv.egovernment.moa.id.util.ParamValidatorUtils; +import at.gv.egovernment.moa.logging.Logger; + +public abstract class OAuth20BaseRequest extends RequestImpl { + + private static final long serialVersionUID = 1L; + + protected Set allowedParameters = new HashSet(); + + protected String getParam(final HttpServletRequest request, final String name, final boolean isNeeded) throws OAuth20Exception { + String param = request.getParameter(name); + Logger.debug("Reading param " + name + " from HttpServletRequest with value " + param); + + if (isNeeded && StringUtils.isEmpty(param)) { + throw new OAuth20WrongParameterException(name); + } + + this.allowedParameters.add(name); + + return param; + } + + protected void populateParameters(final HttpServletRequest request) throws OAuth20Exception { + + // moa id - load oa with client id! + try { + String oaURL = StringEscapeUtils.escapeHtml(this.getParam(request, OAuth20Constants.PARAM_CLIENT_ID, true)); + if (!ParamValidatorUtils.isValidOA(oaURL)) { + throw new OAuth20WrongParameterException(OAuth20Constants.PARAM_CLIENT_ID); + } + this.setOAURL(oaURL); + OAAuthParameter oaParam = AuthConfigurationProvider.getInstance().getOnlineApplicationParameter(oaURL); + + if (oaParam == null) { + throw new OAuth20WrongParameterException(OAuth20Constants.PARAM_CLIENT_ID); + } + this.setTarget(oaParam.getTarget()); + + OAOAUTH20 config = oaParam.getoAuth20Config(); + if (config == null) { + throw new OAuth20InvalidRequestException(); + } + if (StringUtils.isEmpty(config.getOAuthClientSecret()) || StringUtils.isEmpty(config.getOAuthClientId()) + || StringUtils.isEmpty(config.getOAuthRedirectUri())) { + throw new OAuth20ServerErrorException(); + } + } + catch (ConfigurationException e) { + throw new OAuth20WrongParameterException(OAuth20Constants.PARAM_CLIENT_ID); + } + + // oAuth + this.populateSpecialParameters(request); + + // cleanup parameters + this.checkAllowedParameters(request); + } + + private void checkAllowedParameters(final HttpServletRequest request) { + Logger.debug("Going to check for allowed parameters"); + this.allowedParameters.add(OAuth20Constants.PARAM_MOA_ACTION); + this.allowedParameters.add(OAuth20Constants.PARAM_MOA_MOD); + + @SuppressWarnings("rawtypes") + Iterator iter = request.getParameterMap().keySet().iterator(); + while (iter.hasNext()) { + String name = (String) iter.next(); + if (!this.allowedParameters.contains(name)) { + + Logger.debug("Found wrong parameter: " + name); + throw new OAuth20WrongParameterException(name); + } + } + + } + + protected abstract void populateSpecialParameters(final HttpServletRequest request) throws OAuth20Exception; + + public static OAuth20BaseRequest newInstance(final String action, final HttpServletRequest request) throws OAuth20Exception { + OAuth20BaseRequest res; + + if (action.equals(OAuth20Protocol.AUTH_ACTION)) { + res = new OAuth20AuthRequest(); + } else if (action.equals(OAuth20Protocol.TOKEN_ACTION)) { + res = new OAuth20TokenRequest(); + } else { + throw new OAuth20InvalidRequestException(); + } + + res.setAction(action); + res.setModule(OAuth20Protocol.NAME); + + res.populateParameters(request); + return res; + } +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/requests/OAuth20TokenRequest.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/requests/OAuth20TokenRequest.java new file mode 100644 index 000000000..6d69f8238 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/oauth20/requests/OAuth20TokenRequest.java @@ -0,0 +1,118 @@ +package at.gv.egovernment.moa.id.protocols.oauth20.requests; + +import javax.servlet.http.HttpServletRequest; + +import at.gv.egovernment.moa.id.commons.db.dao.config.OAOAUTH20; +import at.gv.egovernment.moa.id.config.ConfigurationException; +import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider; +import at.gv.egovernment.moa.id.protocols.oauth20.OAuth20Constants; +import at.gv.egovernment.moa.id.protocols.oauth20.exceptions.OAuth20AccessDeniedException; +import at.gv.egovernment.moa.id.protocols.oauth20.exceptions.OAuth20Exception; +import at.gv.egovernment.moa.id.protocols.oauth20.exceptions.OAuth20InvalidGrantException; +import at.gv.egovernment.moa.id.protocols.oauth20.exceptions.OAuth20WrongParameterException; + +public class OAuth20TokenRequest extends OAuth20BaseRequest { + + private static final long serialVersionUID = 1L; + + private String code; + private String grantType; + private String clientID; + private String clientSecret; + + /** + * @return the code + */ + public String getCode() { + return code; + } + + /** + * @param code + * the code to set + */ + public void setCode(String code) { + this.code = code; + } + + /** + * @return the grantType + */ + public String getGrantType() { + return grantType; + } + + /** + * @param grantType + * the grantType to set + */ + public void setGrantType(String grantType) { + this.grantType = grantType; + } + + /** + * @return the clientID + */ + public String getClientID() { + return clientID; + } + + /** + * @param clientID + * the clientID to set + */ + public void setClientID(String clientID) { + this.clientID = clientID; + } + + /** + * @return the clientSecret + */ + public String getClientSecret() { + return clientSecret; + } + + /** + * @param clientSecret + * the clientSecret to set + */ + public void setClientSecret(String clientSecret) { + this.clientSecret = clientSecret; + } + + @Override + protected void populateSpecialParameters(HttpServletRequest request) throws OAuth20Exception { + this.setCode(this.getParam(request, OAuth20Constants.RESPONSE_CODE, true)); + this.setGrantType(this.getParam(request, OAuth20Constants.PARAM_GRANT_TYPE, true)); + this.setClientID(this.getParam(request, OAuth20Constants.PARAM_CLIENT_ID, true)); + this.setClientSecret(this.getParam(request, OAuth20Constants.PARAM_CLIENT_SECRET, true)); + + // check for grant type + if (!this.getGrantType().equals(OAuth20Constants.PARAM_GRANT_TYPE_VALUE_AUTHORIZATION_CODE)) { + throw new OAuth20InvalidGrantException(); + } + + // check if client id and secret are ok + try { + // OAOAUTH20 cannot be null at this point. check was done in base request + OAOAUTH20 oAuthConfig = AuthConfigurationProvider.getInstance().getOnlineApplicationParameter(this.getOAURL()) + .getoAuth20Config(); + + if (!this.getClientID().equals(oAuthConfig.getOAuthClientId())) { + throw new OAuth20AccessDeniedException(); + } + + if (!this.getClientSecret().equals(oAuthConfig.getOAuthClientSecret())) { + throw new OAuth20AccessDeniedException(); + } + + } + catch (ConfigurationException e) { + throw new OAuth20WrongParameterException(OAuth20Constants.PARAM_CLIENT_ID); + } + + //add valid parameters + this.allowedParameters.add(OAuth20Constants.PARAM_SCOPE); + this.allowedParameters.add(OAuth20Constants.PARAM_REDIRECT_URI); + } +} diff --git a/id/server/idserverlib/src/main/resources/resources/properties/id_messages_de.properties b/id/server/idserverlib/src/main/resources/resources/properties/id_messages_de.properties index 6b664f692..37e35b6ce 100644 --- a/id/server/idserverlib/src/main/resources/resources/properties/id_messages_de.properties +++ b/id/server/idserverlib/src/main/resources/resources/properties/id_messages_de.properties @@ -217,4 +217,15 @@ pvp2.11=Binding {0} wird nicht unterstuetzt pvp2.12=NameID Format {0} wird nicht unterstuetzt pvp2.13=Interner Server Fehler pvp2.14=SAML Anfrage verweigert -pvp2.15=Keine Metadateninformation gefunden +pvp2.15=Keine Metadateninformation gefunden + + +oauth20.01=Fehlerhafte redirect url +oauth20.02=Fehlender Parameter "{0}" +oauth20.03=Angeforderter response_type ist nicht erlaubt +oauth20.04=Die Art der Anmeldung wird nicht unterstuetzt +oauth20.05=Der angegebene Benutzer ist nicht berechtigt +oauth20.06=Die angegebene OA kann nicht verwendet werden +oauth20.07=Angeforderter grant_type ist nicht erlaubt +oauth20.08=Nicht berechtigt für Token-Request +oauth20.09=Zertifikat fuer JSON Web-Token ist falsch konfiguriert. Fehler bei "{0}" diff --git a/id/server/idserverlib/src/test/java/test/at/gv/egovernment/moa/id/auth/oauth/CertTest.java b/id/server/idserverlib/src/test/java/test/at/gv/egovernment/moa/id/auth/oauth/CertTest.java new file mode 100644 index 000000000..6452d5ae6 --- /dev/null +++ b/id/server/idserverlib/src/test/java/test/at/gv/egovernment/moa/id/auth/oauth/CertTest.java @@ -0,0 +1,86 @@ +package test.at.gv.egovernment.moa.id.auth.oauth; + +import java.security.KeyStore; +import java.security.PrivateKey; +import java.security.cert.X509Certificate; +import java.security.interfaces.RSAPrivateKey; + +import net.oauth.jsontoken.crypto.RsaSHA256Signer; +import net.oauth.jsontoken.crypto.RsaSHA256Verifier; + +import org.opensaml.xml.security.x509.BasicX509Credential; +import org.testng.annotations.Test; + +import at.gv.egovernment.moa.util.KeyStoreUtils; +import at.gv.egovernment.moa.util.StringUtils; +import eu.stork.vidp.messages.exception.SAMLException; + +public class CertTest { + + /** KeyStore Path */ + private String keyStorePath = "file:/D:/dev/work/exthex/workspace/OAuthTesting/resources/keys/test_keystore.jks"; + + /** KeyStore Password */ + private String keyStorePassword = "test12"; + + /** Specific Key Name as Credential */ + private String keyName = "1"; + + /** Key password */ + private String keyPassword = "test12"; + + + + + @Test(enabled = false) + public void loadCert() throws Exception { + + if (StringUtils.isEmpty(this.keyStorePath)) throw new SAMLException("No keyStorePath specified"); + + // KeyStorePassword optional + // if (StringUtils.isEmpty(this.keyStorePassword)) + // throw new SAMLException("No keyStorePassword specified"); + + if (StringUtils.isEmpty(this.keyName)) throw new SAMLException("No keyName specified"); + + // KeyStorePassword optional + // if (StringUtils.isEmpty(this.keyPassword)) + // throw new SAMLException("No keyPassword specified"); + + KeyStore ks = null; + try { + ks = KeyStoreUtils.loadKeyStore(this.keyStorePath, this.keyStorePassword); + } + catch (Exception e) { + e.printStackTrace(); + } + + // return new KeyStoreX509CredentialAdapter(ks, keyName, keyPwd.toCharArray()); + BasicX509Credential credential = null; + try { + java.security.cert.X509Certificate certificate = (X509Certificate) ks.getCertificate(this.keyName); + + PrivateKey privateKey = (PrivateKey) ks.getKey(this.keyName, this.keyPassword.toCharArray()); + credential = new BasicX509Credential(); + credential.setEntityCertificate(certificate); + credential.setPrivateKey(privateKey); + + System.out.println(privateKey); + + } + catch (Exception e) { + e.printStackTrace(); + + } + System.out.println(credential); + + String data = "someData"; + + RsaSHA256Signer signer = new RsaSHA256Signer("signer1", keyName, (RSAPrivateKey) credential.getPrivateKey()); + + byte[] signedData = signer.sign(data.getBytes()); + + RsaSHA256Verifier verifier = new RsaSHA256Verifier(credential.getPublicKey()); + verifier.verifySignature(data.getBytes(), signedData); + } +} diff --git a/id/server/idserverlib/src/test/java/test/at/gv/egovernment/moa/id/auth/oauth/OAuth20ErrorsTests.java b/id/server/idserverlib/src/test/java/test/at/gv/egovernment/moa/id/auth/oauth/OAuth20ErrorsTests.java new file mode 100644 index 000000000..64179d75a --- /dev/null +++ b/id/server/idserverlib/src/test/java/test/at/gv/egovernment/moa/id/auth/oauth/OAuth20ErrorsTests.java @@ -0,0 +1,190 @@ +package test.at.gv.egovernment.moa.id.auth.oauth; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; + +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.methods.GetMethod; +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.Assert; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import at.gv.egovernment.moa.id.protocols.oauth20.OAuth20Constants; +import at.gv.egovernment.moa.id.protocols.oauth20.OAuth20Util; + +import com.google.api.client.extensions.java6.auth.oauth2.VerificationCodeReceiver; +import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver; +import com.google.api.client.http.HttpTransport; +import com.google.api.client.http.javanet.NetHttpTransport; +import com.google.api.client.json.JsonFactory; +import com.google.api.client.json.jackson2.JacksonFactory; + +public class OAuth20ErrorsTests { + + final static Logger log = LoggerFactory.getLogger(OAuth20ErrorsTests.class); + + private static VerificationCodeReceiver receiver; + + // base uri + private static String OAUTH2_BASE_URI = "http://localhost:8080/moa-id-auth/dispatcher"; + // auth action + private static String OAUTH2_AUTH_URI = OAUTH2_BASE_URI + "?mod=id_oauth20&action=AUTH"; + // token action + private static String OAUTH2_TOKEN_URI = OAUTH2_BASE_URI + "?mod=id_oauth20&action=TOKEN"; + + // client id + private static String CLIENT_ID = "http://test"; + // client secret + private static String CLIENT_SECRET = "d435cf0a-3933-48f7-b142-339710c8f070"; + // OAuth 2.0 scopes + private static List SCOPES = Arrays.asList("testScope1", "testScope2"); + // state + private static String STATE = "testState"; + // code + private static String CODE = "code"; + // redirect uri + private static String REDIRECT_URI = "http://localhost:59542/Callback"; + + @BeforeMethod + public void beforeTest() throws Exception { + receiver = new LocalServerReceiver.Builder().setPort(59542).build(); + // REDIRECT_URI = receiver.getRedirectUri(); + // start + receiver.getRedirectUri(); + } + + @AfterMethod + public void afterTest() { + try { + receiver.stop(); + } + catch (IOException e) { + } + } + + private void checkParam(final String paramString, final String paramName) { + String[] help = paramString.split("="); + Assert.assertEquals(help[0], paramName); + Assert.assertTrue(StringUtils.isNotEmpty(help[1])); + } + + private void checkParams(final String queryString) { + // System.out.println("QueryString: " + queryString); + + System.out.println("Result url: " + queryString); + + String[] params = queryString.split("&"); + + this.checkParam(params[0], OAuth20Constants.PARAM_ERROR); + this.checkParam(params[1], OAuth20Constants.PARAM_ERROR_DESCRIPTION); + // this.checkParam(params[2], OAuth20Constants.PARAM_ERROR_URI); + // this.checkParam(params[3], OAuth20Constants.PARAM_STATE); + this.checkParam(params[2], OAuth20Constants.PARAM_STATE); + } + + class OAuthRequestParameters { + String redirectUri; + String clientId; + String responseType; + String scope; + String state; + String error; + + public OAuthRequestParameters(String redirectUri, String clientId, String responseType, String scope, String state, + String error) { + this.redirectUri = redirectUri; + this.clientId = clientId; + this.responseType = responseType; + this.scope = scope; + this.state = state; + this.error = error; + } + } + + @DataProvider(name = "parameter") + public Object[][] parameterProvider() { + // parameter is missing + // OAuthRequestParameters p0 = new OAuthRequestParameters(null, OA_URL, CLIENT_ID, CODE, + // "testScope1", null, + // "User authorization failed (invalid_request)"); + // OAuthRequestParameters p1 = new OAuthRequestParameters(REDIRECT_URI, CLIENT_ID, CODE, + // "testScope1", STATE, + // "User authorization failed (invalid_request)"); + OAuthRequestParameters p2 = new OAuthRequestParameters(REDIRECT_URI, null, CODE, "testScope1", STATE, + "User authorization failed (invalid_request)"); + OAuthRequestParameters p3 = new OAuthRequestParameters(REDIRECT_URI, CLIENT_ID, null, "testScope1", STATE, + "User authorization failed (invalid_request)"); + OAuthRequestParameters p4 = new OAuthRequestParameters(REDIRECT_URI, CLIENT_ID, CODE, null, STATE, null); + OAuthRequestParameters p5 = new OAuthRequestParameters(REDIRECT_URI, CLIENT_ID, CODE, "testScope1", null, + "User authorization failed (invalid_request)"); + + // wrong response type + OAuthRequestParameters p6 = new OAuthRequestParameters(REDIRECT_URI, CLIENT_ID, "WRONG_CODE", "testScope1", STATE, + "User authorization failed (unsupported_response_type)"); + // wrong client id + OAuthRequestParameters p7 = new OAuthRequestParameters(REDIRECT_URI, "wrongClient", CODE, "testScope1", STATE, + "User authorization failed (invalid_request)"); + // wrong redirect uri + // OAuthRequestParameters p9 = new OAuthRequestParameters("wrongURI", OA_URL, "wrongClient", + // CODE, "testScope1", STATE, + // "User authorization failed (access_denied)"); + + return new Object[][] { { p2 }, { p3 }, { p4 }, { p5 }, { p6 }, { p7 } }; + } + + @Test(dataProvider = "parameter", enabled = false) + public void testMissingParams(OAuthRequestParameters p) throws Exception { + StringBuilder url = new StringBuilder(); + url.append(OAUTH2_AUTH_URI); + + if (StringUtils.isNotEmpty(p.redirectUri)) OAuth20Util.addParameterToURL(url, "redirect_uri", p.redirectUri); + if (StringUtils.isNotEmpty(p.clientId)) OAuth20Util.addParameterToURL(url, "client_id", p.clientId); + if (StringUtils.isNotEmpty(p.responseType)) OAuth20Util.addParameterToURL(url, "response_type", p.responseType); + if (StringUtils.isNotEmpty(p.scope)) OAuth20Util.addParameterToURL(url, "scope", p.scope); + if (StringUtils.isNotEmpty(p.state)) OAuth20Util.addParameterToURL(url, "state", p.state); + + String finalUrl = url.toString(); + System.out.println("Calling: " + finalUrl); + + HttpClient client = new HttpClient(); + GetMethod get = new GetMethod(finalUrl); + int res = client.executeMethod(get); + Assert.assertEquals(res, HttpServletResponse.SC_OK); + + // assert + + if (p.error == null) { + Assert.assertFalse(get.getQueryString().contains("error")); + // receiver.waitForCode(); + } else { + // check if all error params are returned + this.checkParams(get.getQueryString()); + try { + receiver.waitForCode(); + Assert.assertTrue(false); + } + catch (Exception e) { + Assert.assertEquals(e.getMessage(), p.error); + } + } + } + + @Test(enabled = false) + public void testTokenErrorResponse() throws Exception { + HttpClient client = new HttpClient(); + GetMethod get = new GetMethod(OAUTH2_TOKEN_URI + "&client_id=" + CLIENT_ID + "&client_secret=" + CLIENT_SECRET + + "&code=test&grant_type=authorization_code"); + int res = client.executeMethod(get); + + System.out.println(res); + System.out.println(get.getResponseBodyAsString()); + } +} diff --git a/id/server/idserverlib/src/test/java/test/at/gv/egovernment/moa/id/auth/oauth/OAuth20GoogleClientTestCase.java b/id/server/idserverlib/src/test/java/test/at/gv/egovernment/moa/id/auth/oauth/OAuth20GoogleClientTestCase.java new file mode 100644 index 000000000..7cf2ac82b --- /dev/null +++ b/id/server/idserverlib/src/test/java/test/at/gv/egovernment/moa/id/auth/oauth/OAuth20GoogleClientTestCase.java @@ -0,0 +1,136 @@ +package test.at.gv.egovernment.moa.id.auth.oauth; + +import java.awt.Desktop; +import java.awt.Desktop.Action; +import java.io.IOException; +import java.math.BigInteger; +import java.net.URI; +import java.security.SecureRandom; +import java.util.Arrays; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.Assert; +import org.testng.annotations.Test; + +import com.google.api.client.auth.oauth2.AuthorizationCodeFlow; +import com.google.api.client.auth.oauth2.AuthorizationCodeRequestUrl; +import com.google.api.client.auth.oauth2.BearerToken; +import com.google.api.client.auth.oauth2.ClientParametersAuthentication; +import com.google.api.client.auth.oauth2.TokenResponse; +import com.google.api.client.auth.openidconnect.IdToken; +import com.google.api.client.extensions.java6.auth.oauth2.VerificationCodeReceiver; +import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver; +import com.google.api.client.http.GenericUrl; +import com.google.api.client.http.HttpExecuteInterceptor; +import com.google.api.client.http.HttpTransport; +import com.google.api.client.http.javanet.NetHttpTransport; +import com.google.api.client.json.JsonFactory; +import com.google.api.client.json.jackson2.JacksonFactory; + +public class OAuth20GoogleClientTestCase { + + final static Logger log = LoggerFactory.getLogger(OAuth20GoogleClientTestCase.class); + + // private static FileDataStoreFactory DATA_STORE_FACTORY; + + // Global instance of the HTTP transport. + private static HttpTransport HTTP_TRANSPORT = new NetHttpTransport(); + // Global instance of the JSON factory. + private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance(); + + private static String ISS = "https://localhost/moa-id-auth/"; + + // base uri + //private static String OAUTH2_BASE_URI = ISS + "dispatcher"; + // auth action + //private static String OAUTH2_AUTH_URI = OAUTH2_BASE_URI + "?mod=id_oauth20&action=AUTH"; + private static String OAUTH2_AUTH_URI = ISS + "oauth2/auth"; + + // token action + //private static String OAUTH2_TOKEN_URI = OAUTH2_BASE_URI + "?mod=id_oauth20&action=TOKEN"; + private static String OAUTH2_TOKEN_URI = ISS + "oauth2/token"; + + // client id + private static String CLIENT_ID = "http://test"; + // client secret + private static String CLIENT_SECRET = "d435cf0a-3933-48f7-b142-339710c8f070"; + // OAuth 2.0 scopes + private static final List SCOPES = Arrays.asList("profile", "eID", "eID_gov", "mandate"); + + // open browser for bku login + private void openURL(String url) { + Assert.assertNotNull(url); + System.out.println(url); + if (Desktop.isDesktopSupported()) { + Desktop desktop = Desktop.getDesktop(); + if (desktop.isSupported(Action.BROWSE)) { + try { + desktop.browse(URI.create(url)); + return; + } + catch (IOException e) { + // handled below + } + } + } + // Finally just ask user to open in their browser using copy-paste + + log.info("Please open the following URL in your browser:"); + log.info(url); + } + + private TokenResponse authorize() throws Exception { + // set up a receiver for the callback + VerificationCodeReceiver receiver = new LocalServerReceiver.Builder().setPort(59542).build(); + + // create AuthorizationCodeFlow + GenericUrl token_uri = new GenericUrl(OAUTH2_TOKEN_URI); + HttpExecuteInterceptor credentials = new ClientParametersAuthentication(CLIENT_ID, CLIENT_SECRET); + AuthorizationCodeFlow flow = new AuthorizationCodeFlow.Builder(BearerToken.queryParameterAccessMethod(), HTTP_TRANSPORT, + JSON_FACTORY, token_uri, credentials, CLIENT_ID, OAUTH2_AUTH_URI).setScopes(SCOPES).build(); + // .setDataStoreFactory(DATA_STORE_FACTORY) + + // create AuthorizationCodeRequestUrl + try { + String redirectUri = receiver.getRedirectUri(); + String state = new BigInteger(130, new SecureRandom()).toString(32); + AuthorizationCodeRequestUrl authorizationUrl = flow.newAuthorizationUrl().setRedirectUri(redirectUri).setState(state); + + // open in browser + this.openURL(authorizationUrl.build()); + + // receive authorization code and exchange it for an access token + String code = receiver.waitForCode(); + System.out.println(code); + TokenResponse response = flow.newTokenRequest(code).setRedirectUri(redirectUri).execute(); + return response; + } + finally { + // if anything fails, stop the receiver + receiver.stop(); + } + + } + + // eyJhbGciOiJSUzI1NiIsImtpZCI6IjEifQ.eyJpc3MiOiJodHRwczovL2xvY2FsaG9zdC9tb2EtaWQtYXV0aC8iLCJleHAiOi02MzE5MDMsInN1YiI6IncveThQY2pNTHBFTGZmUHRTSDNtbmd6M24rRVx1MDAzZCIsImJpcnRoZGF0ZSI6IjE5ODUtMDItMDEiLCJmYW1pbHlfbmFtZSI6IkhpZXNzIiwiZ2l2ZW5fbmFtZSI6Ik1pY2hhZWwiLCJpYXQiOi02MzIyMDN9.Z_jveITHlTtktPOOV3n_sMbg50YQ4YcOEcSUs_RJ-4FGedj1sVxk9gmlUQcBPfQaBrPgC6RoiPLTy8CKu2PBClEyv9c9HdzIGqBjWzaTSNASx_QL5bfG4EQ8VZmSEI9d0whzlaBgkUFNfhx-Q2ZVh-g8SJ-0JO0zFR18OSRNTxPTJ4PPl0APqn2H-98sU331_zQKiZxNOvl_6OG26VoIYwEuW5m_N5tsf4lLAlqYcdHR3iNTeu8AkAOvlEwv7Z3BeeOiP4u-OWuc6VusWBPxaI2NwmDIoorpyIxY-wEFb4CWICuyk61Wlq1SCNdl-f-ODwJBK3rlj0IMlYbAjKSB0g + private void verifyIdToken(TokenResponse response) throws Exception { + String id_token = (String) response.getUnknownKeys().get("id_token"); + log.info("going to parse id token: {}", id_token); + + IdToken idToken = IdToken.parse(JSON_FACTORY, id_token); + Assert.assertTrue(idToken.verifyIssuer(ISS)); + + log.info(idToken.getPayload().toPrettyString()); + } + + @Test(enabled = false) + public void testServerFlow() throws Exception { + TokenResponse response = this.authorize(); + log.info(response.toPrettyString()); + + this.verifyIdToken(response); + } + +} diff --git a/id/server/idserverlib/src/test/java/test/at/gv/egovernment/moa/id/auth/oauth/OAuth20UtilTest.java b/id/server/idserverlib/src/test/java/test/at/gv/egovernment/moa/id/auth/oauth/OAuth20UtilTest.java new file mode 100644 index 000000000..83b92dbad --- /dev/null +++ b/id/server/idserverlib/src/test/java/test/at/gv/egovernment/moa/id/auth/oauth/OAuth20UtilTest.java @@ -0,0 +1,48 @@ +package test.at.gv.egovernment.moa.id.auth.oauth; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.testng.Assert; +import org.testng.annotations.Test; + +import at.gv.egovernment.moa.id.protocols.oauth20.OAuth20Util; + +public class OAuth20UtilTest { + + @Test + public void validateURL() { + Assert.assertTrue(OAuth20Util.isUrl("file:/D:/dev/work/exthex/workspace/OAuthTesting/resources/keys/test_keystore.jks")); + Assert.assertTrue(OAuth20Util.isUrl("https://www.google.at/")); + Assert.assertTrue(OAuth20Util.isUrl("http://test")); + Assert.assertTrue(OAuth20Util.isUrl("http://localhost:59542/Callback")); + + + Assert.assertFalse(OAuth20Util.isUrl("http://")); + Assert.assertFalse(OAuth20Util.isUrl("123http://test")); + Assert.assertFalse(OAuth20Util.isUrl("test")); + } + + @Test + public void validateState() { + // check state for invalid characters (like < > & ; ... javascript ... to prevent xss) + + Assert.assertFalse(OAuth20Util.isValidStateValue("javascript")); + Assert.assertFalse(OAuth20Util.isValidStateValue("")); + Assert.assertFalse(OAuth20Util.isValidStateValue("Tasst")); + Assert.assertFalse(OAuth20Util.isValidStateValue("Tes&t")); + Assert.assertFalse(OAuth20Util.isValidStateValue("Tes;t")); + Assert.assertTrue(OAuth20Util.isValidStateValue("secure_state")); + } + + + @Test + public void testExp() { + Pattern urlPattern = Pattern.compile("/oauth2/auth\\?(.*)$", Pattern.CASE_INSENSITIVE); + Matcher matcher = urlPattern.matcher("https://localhost/moa-id-auth/oauth2/auth?client_id=http://test&redirect_uri=http://localhost:59542/Callback&response_type=code&scope=profile%20eID%20eID_gov%20mandate&state=7gfnabf112ogg9segnnrfpi83q"); + System.out.println(matcher.find()); + } + +} -- cgit v1.2.3