diff options
Diffstat (limited to 'eaaf_modules/eaaf_module_pvp2_idp/src')
23 files changed, 1768 insertions, 1826 deletions
diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/PVP2SProfileIDPSpringResourceProvider.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/PVP2SProfileIDPSpringResourceProvider.java deleted file mode 100644 index d50c5ee4..00000000 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/PVP2SProfileIDPSpringResourceProvider.java +++ /dev/null @@ -1,54 +0,0 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. - * - * Licensed under the EUPL, Version 1.2 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: - * https://joinup.ec.europa.eu/news/understanding-eupl-v12 - * - * 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.egiz.eaaf.modules.pvp2.idp; - -import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.Resource; - -import at.gv.egiz.components.spring.api.SpringResourceProvider; - -public class PVP2SProfileIDPSpringResourceProvider implements SpringResourceProvider { - - @Override - public String getName() { - return "EAAF PVP2 S-Profile IDP SpringResourceProvider"; - } - - @Override - public String[] getPackagesToScan() { - // TODO Auto-generated method stub - return null; - } - - @Override - public Resource[] getResourcesToLoad() { - ClassPathResource sl20AuthConfig = new ClassPathResource("/eaaf_pvp_idp.beans.xml", PVP2SProfileIDPSpringResourceProvider.class); - - return new Resource[] {sl20AuthConfig}; - } - -} diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/Pvp2SProfileIdpSpringResourceProvider.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/Pvp2SProfileIdpSpringResourceProvider.java new file mode 100644 index 00000000..9414dc33 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/Pvp2SProfileIdpSpringResourceProvider.java @@ -0,0 +1,47 @@ +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 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: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * 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.egiz.eaaf.modules.pvp2.idp; + +import at.gv.egiz.components.spring.api.SpringResourceProvider; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; + +public class Pvp2SProfileIdpSpringResourceProvider implements SpringResourceProvider { + + @Override + public String getName() { + return "EAAF PVP2 S-Profile IDP SpringResourceProvider"; + } + + @Override + public String[] getPackagesToScan() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Resource[] getResourcesToLoad() { + final ClassPathResource sl20AuthConfig = new ClassPathResource("/eaaf_pvp_idp.beans.xml", + Pvp2SProfileIdpSpringResourceProvider.class); + + return new Resource[] {sl20AuthConfig}; + } + +} diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/api/builder/ISubjectNameIdGenerator.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/api/builder/ISubjectNameIdGenerator.java index 90662f48..131be543 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/api/builder/ISubjectNameIdGenerator.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/api/builder/ISubjectNameIdGenerator.java @@ -1,45 +1,39 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. * - * Licensed under the EUPL, Version 1.2 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: + * Licensed under the EUPL, Version 1.2 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: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * - * 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. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ + * 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.egiz.eaaf.modules.pvp2.idp.api.builder; import at.gv.egiz.eaaf.core.api.idp.IAuthData; -import at.gv.egiz.eaaf.core.api.idp.ISPConfiguration; +import at.gv.egiz.eaaf.core.api.idp.IspConfiguration; import at.gv.egiz.eaaf.core.impl.data.Pair; -import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2Exception; +import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2Exception; public interface ISubjectNameIdGenerator { - /** - * Generates a SAML2 subjectNameId from authentication data - * - * @param authData Authentication data for the current pending request - * @param spConfig Service provider configuration - * @return Pair of subjectNameId and NameIdFormat - * @throws PVP2Exception - */ - public Pair<String, String> generateSubjectNameId(IAuthData authData, ISPConfiguration spConfig) throws PVP2Exception; + /** + * Generates a SAML2 subjectNameId from authentication data. + * + * @param authData Authentication data for the current pending request + * @param spConfig Service provider configuration + * @return Pair of subjectNameId and NameIdFormat + * @throws Pvp2Exception In case of an error + */ + public Pair<String, String> generateSubjectNameId(IAuthData authData, IspConfiguration spConfig) + throws Pvp2Exception; } diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/InvalidAssertionConsumerServiceException.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/InvalidAssertionConsumerServiceException.java index 42424726..6d868558 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/InvalidAssertionConsumerServiceException.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/InvalidAssertionConsumerServiceException.java @@ -1,54 +1,47 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. * - * Licensed under the EUPL, Version 1.2 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: + * Licensed under the EUPL, Version 1.2 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: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * - * 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. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ + * 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.egiz.eaaf.modules.pvp2.idp.exception; +import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2Exception; import org.opensaml.saml2.core.StatusCode; -import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2Exception; +public class InvalidAssertionConsumerServiceException extends Pvp2Exception { + + private static final long serialVersionUID = 7861790149343943091L; + + public InvalidAssertionConsumerServiceException(final int idx) { + super("pvp2.28", new Object[] {idx}); + this.statusCodeValue = StatusCode.REQUESTER_URI; + } -public class InvalidAssertionConsumerServiceException extends PVP2Exception { + /** + * Invalid assertion consumer-service URL. + * + * @param wrongUrl invalid URL + */ + public InvalidAssertionConsumerServiceException(final String wrongUrl) { + super("pvp2.23", new Object[] {wrongUrl}); + this.statusCodeValue = StatusCode.REQUESTER_URI; - public InvalidAssertionConsumerServiceException(int idx) { - super("pvp2.28", new Object[]{idx}); - this.statusCodeValue = StatusCode.REQUESTER_URI; - } + } - /** - * - */ - public InvalidAssertionConsumerServiceException(String wrongURL) { - super("pvp2.23", new Object[]{wrongURL}); - this.statusCodeValue = StatusCode.REQUESTER_URI; - - } - /** - * - */ - private static final long serialVersionUID = 7861790149343943091L; } diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/InvalidAssertionEncryptionException.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/InvalidAssertionEncryptionException.java index 55c94df1..0d75616a 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/InvalidAssertionEncryptionException.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/InvalidAssertionEncryptionException.java @@ -1,42 +1,34 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. * - * Licensed under the EUPL, Version 1.2 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: + * Licensed under the EUPL, Version 1.2 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: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * - * 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. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ + * 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.egiz.eaaf.modules.pvp2.idp.exception; +import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2Exception; import org.opensaml.saml2.core.StatusCode; -import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2Exception; - -public class InvalidAssertionEncryptionException extends PVP2Exception { +public class InvalidAssertionEncryptionException extends Pvp2Exception { - private static final long serialVersionUID = 6513388841485355549L; + private static final long serialVersionUID = 6513388841485355549L; - public InvalidAssertionEncryptionException() { - super("pvp2.16", new Object[]{}); - this.statusCodeValue = StatusCode.RESPONDER_URI; - } + public InvalidAssertionEncryptionException() { + super("pvp2.16", new Object[] {}); + this.statusCodeValue = StatusCode.RESPONDER_URI; + } } diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/RequestDeniedException.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/RequestDeniedException.java index 6109c78d..ecceea12 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/RequestDeniedException.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/RequestDeniedException.java @@ -1,45 +1,34 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. * - * Licensed under the EUPL, Version 1.2 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: + * Licensed under the EUPL, Version 1.2 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: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * - * 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. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ + * 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.egiz.eaaf.modules.pvp2.idp.exception; +import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2Exception; import org.opensaml.saml2.core.StatusCode; -import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2Exception; - -public class RequestDeniedException extends PVP2Exception { +public class RequestDeniedException extends Pvp2Exception { - public RequestDeniedException() { - super("pvp2.14", null); - this.statusCodeValue = StatusCode.REQUEST_DENIED_URI; - } + private static final long serialVersionUID = 4415896615794730553L; - /** - * - */ - private static final long serialVersionUID = 4415896615794730553L; + public RequestDeniedException() { + super("pvp2.14", null); + this.statusCodeValue = StatusCode.REQUEST_DENIED_URI; + } } diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/ResponderErrorException.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/ResponderErrorException.java index 7f565c00..331e11cd 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/ResponderErrorException.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/ResponderErrorException.java @@ -1,50 +1,39 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. * - * Licensed under the EUPL, Version 1.2 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: + * Licensed under the EUPL, Version 1.2 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: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * - * 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. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ + * 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.egiz.eaaf.modules.pvp2.idp.exception; +import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2Exception; import org.opensaml.saml2.core.StatusCode; -import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2Exception; +public class ResponderErrorException extends Pvp2Exception { -public class ResponderErrorException extends PVP2Exception { + private static final long serialVersionUID = -425416760138285446L; - /** - * - */ - private static final long serialVersionUID = -425416760138285446L; + public ResponderErrorException(final String messageId, final Object[] parameters, + final Throwable wrapped) { + super(messageId, parameters, wrapped); + this.statusCodeValue = StatusCode.RESPONDER_URI; + } - public ResponderErrorException(String messageId, Object[] parameters, - Throwable wrapped) { - super(messageId, parameters, wrapped); - this.statusCodeValue = StatusCode.RESPONDER_URI; - } - - public ResponderErrorException(String messageId, Object[] parameters) { - super(messageId, parameters); - this.statusCodeValue = StatusCode.RESPONDER_URI; - } + public ResponderErrorException(final String messageId, final Object[] parameters) { + super(messageId, parameters); + this.statusCodeValue = StatusCode.RESPONDER_URI; + } } diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SAMLRequestNotSignedException.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SAMLRequestNotSignedException.java deleted file mode 100644 index a0fad363..00000000 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SAMLRequestNotSignedException.java +++ /dev/null @@ -1,50 +0,0 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. - * - * Licensed under the EUPL, Version 1.2 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: - * https://joinup.ec.europa.eu/news/understanding-eupl-v12 - * - * 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.egiz.eaaf.modules.pvp2.idp.exception; - -import org.opensaml.saml2.core.StatusCode; - -import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2Exception; - -public class SAMLRequestNotSignedException extends PVP2Exception { - - public SAMLRequestNotSignedException() { - super("pvp2.07", null); - this.statusCodeValue = StatusCode.REQUESTER_URI; - } - - public SAMLRequestNotSignedException(Throwable e) { - super("pvp2.07", null, e); - this.statusCodeValue = StatusCode.REQUESTER_URI; - } - - /** - * - */ - private static final long serialVersionUID = 1L; - -} diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SAMLRequestNotSupported.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SAMLRequestNotSupported.java deleted file mode 100644 index e59ebe0a..00000000 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SAMLRequestNotSupported.java +++ /dev/null @@ -1,46 +0,0 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. - * - * Licensed under the EUPL, Version 1.2 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: - * https://joinup.ec.europa.eu/news/understanding-eupl-v12 - * - * 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.egiz.eaaf.modules.pvp2.idp.exception; - -import org.opensaml.saml2.core.StatusCode; - -import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2Exception; - - -public class SAMLRequestNotSupported extends PVP2Exception { - - public SAMLRequestNotSupported() { - super("pvp2.09", null); - this.statusCodeValue = StatusCode.REQUEST_UNSUPPORTED_URI; - } - - /** - * - */ - private static final long serialVersionUID = 1244883178458802767L; - -} diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SamlRequestNotSignedException.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SamlRequestNotSignedException.java new file mode 100644 index 00000000..4650506d --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SamlRequestNotSignedException.java @@ -0,0 +1,42 @@ +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 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: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * 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.egiz.eaaf.modules.pvp2.idp.exception; + +import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2Exception; +import org.opensaml.saml2.core.StatusCode; + +public class SamlRequestNotSignedException extends Pvp2Exception { + + private static final long serialVersionUID = 1L; + + public SamlRequestNotSignedException() { + super("pvp2.07", null); + this.statusCodeValue = StatusCode.REQUESTER_URI; + } + + public SamlRequestNotSignedException(final Throwable e) { + super("pvp2.07", null, e); + this.statusCodeValue = StatusCode.REQUESTER_URI; + } + + + + +} diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SamlRequestNotSupported.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SamlRequestNotSupported.java new file mode 100644 index 00000000..58a493b9 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SamlRequestNotSupported.java @@ -0,0 +1,39 @@ +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 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: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * 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.egiz.eaaf.modules.pvp2.idp.exception; + +import org.opensaml.saml2.core.StatusCode; + +import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2Exception; + + +public class SamlRequestNotSupported extends Pvp2Exception { + + private static final long serialVersionUID = 1244883178458802767L; + + public SamlRequestNotSupported() { + super("pvp2.09", null); + this.statusCodeValue = StatusCode.REQUEST_UNSUPPORTED_URI; + } + + + + +} diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/UnprovideableAttributeException.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/UnprovideableAttributeException.java index 0dfda55f..41252b78 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/UnprovideableAttributeException.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/UnprovideableAttributeException.java @@ -1,43 +1,33 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. * - * Licensed under the EUPL, Version 1.2 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: + * Licensed under the EUPL, Version 1.2 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: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * - * 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. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ + * 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.egiz.eaaf.modules.pvp2.idp.exception; +import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2Exception; import org.opensaml.saml2.core.StatusCode; -import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2Exception; +public class UnprovideableAttributeException extends Pvp2Exception { -public class UnprovideableAttributeException extends PVP2Exception { - /** - * - */ - private static final long serialVersionUID = 3972197758163647157L; + private static final long serialVersionUID = 3972197758163647157L; - public UnprovideableAttributeException(String attributeName) { - super("pvp2.10", new Object[] {attributeName}); - this.statusCodeValue = StatusCode.UNKNOWN_ATTR_PROFILE_URI; - } + public UnprovideableAttributeException(final String attributeName) { + super("pvp2.10", new Object[] {attributeName}); + this.statusCodeValue = StatusCode.UNKNOWN_ATTR_PROFILE_URI; + } } diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AbstractPVP2XProtocol.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AbstractPVP2XProtocol.java deleted file mode 100644 index 3298559a..00000000 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AbstractPVP2XProtocol.java +++ /dev/null @@ -1,541 +0,0 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. - * - * Licensed under the EUPL, Version 1.2 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: - * https://joinup.ec.europa.eu/news/understanding-eupl-v12 - * - * 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.egiz.eaaf.modules.pvp2.idp.impl; - -import java.util.List; - -import javax.annotation.PostConstruct; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.lang.StringEscapeUtils; -import org.apache.commons.lang3.StringUtils; -import org.joda.time.DateTime; -import org.opensaml.common.xml.SAMLConstants; -import org.opensaml.saml2.core.AuthnRequest; -import org.opensaml.saml2.core.Issuer; -import org.opensaml.saml2.core.NameID; -import org.opensaml.saml2.core.Response; -import org.opensaml.saml2.core.Status; -import org.opensaml.saml2.core.StatusCode; -import org.opensaml.saml2.core.StatusMessage; -import org.opensaml.saml2.metadata.AssertionConsumerService; -import org.opensaml.saml2.metadata.EntityDescriptor; -import org.opensaml.saml2.metadata.SPSSODescriptor; -import org.opensaml.ws.security.SecurityPolicyException; -import org.opensaml.xml.security.x509.X509Credential; -import org.opensaml.xml.signature.SignableXMLObject; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; - -import at.gv.egiz.components.eventlog.api.EventConstants; -import at.gv.egiz.eaaf.core.api.IRequest; -import at.gv.egiz.eaaf.core.api.data.EAAFConstants; -import at.gv.egiz.eaaf.core.api.idp.IModulInfo; -import at.gv.egiz.eaaf.core.api.logging.IRevisionLogger; -import at.gv.egiz.eaaf.core.exceptions.AuthnRequestValidatorException; -import at.gv.egiz.eaaf.core.exceptions.EAAFException; -import at.gv.egiz.eaaf.core.exceptions.InvalidProtocolRequestException; -import at.gv.egiz.eaaf.core.exceptions.NoPassivAuthenticationException; -import at.gv.egiz.eaaf.core.exceptions.SLOException; -import at.gv.egiz.eaaf.core.impl.idp.controller.AbstractController; -import at.gv.egiz.eaaf.modules.pvp2.PVPEventConstants; -import at.gv.egiz.eaaf.modules.pvp2.api.IPVP2BasicConfiguration; -import at.gv.egiz.eaaf.modules.pvp2.api.binding.IEncoder; -import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPVPMetadataProvider; -import at.gv.egiz.eaaf.modules.pvp2.api.validation.IAuthnRequestValidator; -import at.gv.egiz.eaaf.modules.pvp2.exception.InvalidPVPRequestException; -import at.gv.egiz.eaaf.modules.pvp2.exception.NameIDFormatNotSupportedException; -import at.gv.egiz.eaaf.modules.pvp2.exception.NoMetadataInformationException; -import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2Exception; -import at.gv.egiz.eaaf.modules.pvp2.idp.exception.InvalidAssertionConsumerServiceException; -import at.gv.egiz.eaaf.modules.pvp2.impl.binding.PostBinding; -import at.gv.egiz.eaaf.modules.pvp2.impl.binding.RedirectBinding; -import at.gv.egiz.eaaf.modules.pvp2.impl.binding.SoapBinding; -import at.gv.egiz.eaaf.modules.pvp2.impl.message.InboundMessage; -import at.gv.egiz.eaaf.modules.pvp2.impl.message.PVPSProfileRequest; -import at.gv.egiz.eaaf.modules.pvp2.impl.utils.AbstractCredentialProvider; -import at.gv.egiz.eaaf.modules.pvp2.impl.utils.SAML2Utils; -import at.gv.egiz.eaaf.modules.pvp2.impl.validation.EAAFURICompare; -import at.gv.egiz.eaaf.modules.pvp2.impl.validation.TrustEngineFactory; -import at.gv.egiz.eaaf.modules.pvp2.impl.verification.SAMLVerificationEngine; - -public abstract class AbstractPVP2XProtocol extends AbstractController implements IModulInfo { - private static final Logger log = LoggerFactory.getLogger(AbstractPVP2XProtocol.class); - - @Autowired(required=true) protected IPVP2BasicConfiguration pvpBasicConfiguration; - @Autowired(required=true) protected IPVPMetadataProvider metadataProvider; - @Autowired(required=true) protected SAMLVerificationEngine samlVerificationEngine; - @Autowired(required=true) protected IAuthnRequestValidator authRequestValidator; - - private AbstractCredentialProvider pvpIDPCredentials; - - - - /** - * Sets a specific credential provider for PVP S-Profile IDP component. - * @param pvpIDPCredentials credential provider - */ - public void setPvpIDPCredentials(AbstractCredentialProvider pvpIDPCredentials) { - this.pvpIDPCredentials = pvpIDPCredentials; - - } - - public boolean generateErrorMessage(Throwable e, - HttpServletRequest request, HttpServletResponse response, - IRequest protocolRequest) throws Throwable { - - if(protocolRequest == null) { - throw e; - } - - if(!(protocolRequest instanceof PVPSProfilePendingRequest) ) { - throw e; - } - PVPSProfilePendingRequest pvpRequest = (PVPSProfilePendingRequest)protocolRequest; - - Response samlResponse = - SAML2Utils.createSAMLObject(Response.class); - Status status = SAML2Utils.createSAMLObject(Status.class); - StatusCode statusCode = SAML2Utils.createSAMLObject(StatusCode.class); - StatusMessage statusMessage = SAML2Utils.createSAMLObject(StatusMessage.class); - - String moaError = null; - - if(e instanceof NoPassivAuthenticationException) { - statusCode.setValue(StatusCode.NO_PASSIVE_URI); - statusMessage.setMessage(StringEscapeUtils.escapeXml(e.getLocalizedMessage())); - - } else if (e instanceof NameIDFormatNotSupportedException) { - statusCode.setValue(StatusCode.INVALID_NAMEID_POLICY_URI); - statusMessage.setMessage(StringEscapeUtils.escapeXml(e.getLocalizedMessage())); - - } else if (e instanceof SLOException) { - //SLOExecpetions only occurs if session information is lost - return false; - - } else if(e instanceof PVP2Exception) { - PVP2Exception ex = (PVP2Exception) e; - statusCode.setValue(ex.getStatusCodeValue()); - String statusMessageValue = ex.getStatusMessageValue(); - if(statusMessageValue != null) { - statusMessage.setMessage(StringEscapeUtils.escapeXml(statusMessageValue)); - } - moaError = statusMessager.mapInternalErrorToExternalError(ex.getErrorId()); - - } else { - statusCode.setValue(StatusCode.RESPONDER_URI); - statusMessage.setMessage(StringEscapeUtils.escapeXml(e.getLocalizedMessage())); - moaError = statusMessager.getResponseErrorCode(e); - } - - - if (StringUtils.isNotEmpty(moaError)) { - StatusCode moaStatusCode = SAML2Utils.createSAMLObject(StatusCode.class); - moaStatusCode.setValue(moaError); - statusCode.setStatusCode(moaStatusCode); - } - - status.setStatusCode(statusCode); - if(statusMessage.getMessage() != null) { - status.setStatusMessage(statusMessage); - } - samlResponse.setStatus(status); - String remoteSessionID = SAML2Utils.getSecureIdentifier(); - samlResponse.setID(remoteSessionID); - - samlResponse.setIssueInstant(new DateTime()); - Issuer nissuer = SAML2Utils.createSAMLObject(Issuer.class); - nissuer.setValue(pvpBasicConfiguration.getIDPEntityId(pvpRequest.getAuthURL())); - nissuer.setFormat(NameID.ENTITY); - samlResponse.setIssuer(nissuer); - - IEncoder encoder = null; - - if(pvpRequest.getBinding().equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI)) { - encoder = applicationContext.getBean("PVPRedirectBinding", RedirectBinding.class); - - } else if(pvpRequest.getBinding().equals(SAMLConstants.SAML2_POST_BINDING_URI)) { - encoder = applicationContext.getBean("PVPPOSTBinding", PostBinding.class); - - } else if (pvpRequest.getBinding().equals(SAMLConstants.SAML2_SOAP11_BINDING_URI)) { - encoder = applicationContext.getBean("PVPSOAPBinding", SoapBinding.class); - } - - if(encoder == null) { - // default to redirect binding - encoder = new RedirectBinding(); - } - - String relayState = null; - if (pvpRequest.getRequest() != null) - relayState = pvpRequest.getRequest().getRelayState(); - - X509Credential signCred = pvpIDPCredentials.getIDPAssertionSigningCredential(); - - encoder.encodeRespone(request, response, samlResponse, pvpRequest.getConsumerURL(), - relayState, signCred, protocolRequest); - return true; - } - - public boolean validate(HttpServletRequest request, - HttpServletResponse response, IRequest pending) { - - return true; - } - - protected void pvpMetadataRequest(HttpServletRequest req, HttpServletResponse resp) throws EAAFException { - //create pendingRequest object - PVPSProfilePendingRequest pendingReq = applicationContext.getBean(PVPSProfilePendingRequest.class); - pendingReq.initialize(req, authConfig); - pendingReq.setModule(getName()); - - revisionsLogger.logEvent( - pendingReq.getUniqueSessionIdentifier(), - pendingReq.getUniqueTransactionIdentifier(), - EventConstants.TRANSACTION_IP, - req.getRemoteAddr()); - - MetadataAction metadataAction = applicationContext.getBean(MetadataAction.class); - metadataAction.processRequest(pendingReq, - req, resp, null); - - } - - protected void PVPIDPPostRequest(HttpServletRequest req, HttpServletResponse resp) throws EAAFException { - PVPSProfilePendingRequest pendingReq = null; - - try { - //create pendingRequest object - pendingReq = applicationContext.getBean(PVPSProfilePendingRequest.class); - pendingReq.initialize(req, authConfig); - pendingReq.setModule(getName()); - - revisionsLogger.logEvent(EventConstants.SESSION_CREATED, pendingReq.getUniqueSessionIdentifier()); - revisionsLogger.logEvent(EventConstants.TRANSACTION_CREATED, pendingReq.getUniqueTransactionIdentifier()); - revisionsLogger.logEvent( - pendingReq.getUniqueSessionIdentifier(), - pendingReq.getUniqueTransactionIdentifier(), - EventConstants.TRANSACTION_IP, - req.getRemoteAddr()); - - //get POST-Binding decoder implementation - InboundMessage msg = (InboundMessage) new PostBinding().decode( - req, resp, metadataProvider, false, - new EAAFURICompare(pvpBasicConfiguration.getIDPSSOPostService(pendingReq.getAuthURL()))); - pendingReq.setRequest(msg); - - //preProcess Message - preProcess(req, resp, pendingReq); - - } catch (SecurityPolicyException e) { - String samlRequest = req.getParameter("SAMLRequest"); - log.warn("Receive INVALID protocol request: " + samlRequest, e); - - //write revision log entries - if (pendingReq != null) - revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, pendingReq.getUniqueTransactionIdentifier()); - - throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}); - - } catch (SecurityException e) { - String samlRequest = req.getParameter("SAMLRequest"); - log.warn("Receive INVALID protocol request: " + samlRequest, e); - - //write revision log entries - if (pendingReq != null) - revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, pendingReq.getUniqueTransactionIdentifier()); - - throw new InvalidProtocolRequestException("pvp2.22", new Object[] {e.getMessage()}); - - } catch (EAAFException e) { - - //write revision log entries - if (pendingReq != null) - revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, pendingReq.getUniqueTransactionIdentifier()); - - throw e; - - } catch (Throwable e) { - String samlRequest = req.getParameter("SAMLRequest"); - log.warn("Receive INVALID protocol request: " + samlRequest, e); - - //write revision log entries - if (pendingReq != null) - revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, pendingReq.getUniqueTransactionIdentifier()); - - throw new EAAFException("pvp2.24", new Object[] {e.getMessage()}, e); - } - } - - protected void PVPIDPRedirecttRequest(HttpServletRequest req, HttpServletResponse resp) throws EAAFException { - PVPSProfilePendingRequest pendingReq = null; - try { - //create pendingRequest object - pendingReq = applicationContext.getBean(PVPSProfilePendingRequest.class); - pendingReq.initialize(req, authConfig); - pendingReq.setModule(getName()); - - revisionsLogger.logEvent(EventConstants.SESSION_CREATED, pendingReq.getUniqueSessionIdentifier()); - revisionsLogger.logEvent(EventConstants.TRANSACTION_CREATED, pendingReq.getUniqueTransactionIdentifier()); - revisionsLogger.logEvent( - pendingReq.getUniqueSessionIdentifier(), - pendingReq.getUniqueTransactionIdentifier(), - EventConstants.TRANSACTION_IP, - req.getRemoteAddr()); - - //get POST-Binding decoder implementation - InboundMessage msg = (InboundMessage) new RedirectBinding().decode( - req, resp, metadataProvider, false, - new EAAFURICompare(pvpBasicConfiguration.getIDPSSORedirectService(pendingReq.getAuthURL()))); - pendingReq.setRequest(msg); - - //preProcess Message - preProcess(req, resp, pendingReq); - - } catch (SecurityPolicyException e) { - String samlRequest = req.getParameter("SAMLRequest"); - log.warn("Receive INVALID protocol request: " + samlRequest, e); - - //write revision log entries - if (pendingReq != null) - revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, pendingReq.getUniqueTransactionIdentifier()); - - throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}); - - } catch (SecurityException e) { - String samlRequest = req.getParameter("SAMLRequest"); - log.warn("Receive INVALID protocol request: " + samlRequest, e); - - //write revision log entries - if (pendingReq != null) - revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, pendingReq.getUniqueTransactionIdentifier()); - - throw new InvalidProtocolRequestException("pvp2.22", new Object[] {e.getMessage()}); - - } catch (EAAFException e) { - String samlRequest = req.getParameter("SAMLRequest"); - log.info("Receive INVALID protocol request: " + samlRequest); - - //write revision log entries - if (pendingReq != null) - revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, pendingReq.getUniqueTransactionIdentifier()); - - throw e; - - } catch (Throwable e) { - String samlRequest = req.getParameter("SAMLRequest"); - log.warn("Receive INVALID protocol request: " + samlRequest, e); - - //write revision log entries - if (pendingReq != null) - revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, pendingReq.getUniqueTransactionIdentifier()); - - throw new EAAFException("pvp2.24", new Object[] {e.getMessage()}, e); - } - } - - - - /** - * - * - * @param request - * @param response - * @param msg - * @return true if preprocess can handle this request type, otherwise false - * @throws Throwable - */ - abstract protected boolean childPreProcess(HttpServletRequest request, - HttpServletResponse response, PVPSProfilePendingRequest pendingReq) throws Throwable; - - protected void preProcess(HttpServletRequest request, - HttpServletResponse response, PVPSProfilePendingRequest pendingReq) throws Throwable { - - InboundMessage msg = pendingReq.getRequest(); - - if (StringUtils.isEmpty(msg.getEntityID())) { - throw new InvalidProtocolRequestException("pvp2.20", new Object[] {}); - - } - - if(!msg.isVerified()) { - samlVerificationEngine.verify(msg, - TrustEngineFactory.getSignatureKnownKeysTrustEngine(metadataProvider)); - msg.setVerified(true); - - } - - revisionsLogger.logEvent(pendingReq, IRevisionLogger.AUTHPROTOCOL_TYPE, getAuthProtocolIdentifier()); - - if (msg instanceof PVPSProfileRequest && - ((PVPSProfileRequest)msg).getSamlRequest() instanceof AuthnRequest) - preProcessAuthRequest(request, response, pendingReq); - - else if (childPreProcess(request, response, pendingReq)) - log.debug("Find protocol handler in child implementation"); - - else { - log.error("Receive unsupported PVP21 message of type: " + ((PVPSProfileRequest)msg).getSamlRequest().getClass().getName()); - throw new InvalidPVPRequestException("pvp2.09", - new Object[] {((PVPSProfileRequest)msg).getSamlRequest().getClass().getName()}); - } - - - - //switch to session authentication - protAuthService.performAuthentication(request, response, pendingReq); - } - - - /** - * PreProcess Authn request - * @param request - * @param response - * @param pendingReq - * @throws Throwable - */ - private void preProcessAuthRequest(HttpServletRequest request, - HttpServletResponse response, PVPSProfilePendingRequest pendingReq) throws Throwable { - - PVPSProfileRequest moaRequest = ((PVPSProfileRequest)pendingReq.getRequest()); - SignableXMLObject samlReq = moaRequest.getSamlRequest(); - - if(!(samlReq instanceof AuthnRequest)) { - throw new InvalidPVPRequestException("Unsupported request", new Object[] {}); - } - - EntityDescriptor metadata = moaRequest.getEntityMetadata(metadataProvider); - if(metadata == null) { - throw new NoMetadataInformationException(); - } - SPSSODescriptor spSSODescriptor = metadata.getSPSSODescriptor(SAMLConstants.SAML20P_NS); - - AuthnRequest authnRequest = (AuthnRequest)samlReq; - - if (authnRequest.getIssueInstant() == null) { - log.warn("Unsupported request: No IssueInstant Attribute found."); - throw new AuthnRequestValidatorException("pvp2.22", - new Object[] {"Unsupported request: No IssueInstant Attribute found"}, - pendingReq); - - } - - if (authnRequest.getIssueInstant().minusMinutes(EAAFConstants.ALLOWED_TIME_JITTER).isAfterNow()) { - log.warn("Unsupported request: No IssueInstant DateTime is not valid anymore."); - throw new AuthnRequestValidatorException("pvp2.22", - new Object[] {"Unsupported request: No IssueInstant DateTime is not valid anymore."}, - pendingReq); - - } - - //parse AssertionConsumerService - AssertionConsumerService consumerService = null; - if (StringUtils.isNotEmpty(authnRequest.getAssertionConsumerServiceURL()) && - StringUtils.isNotEmpty(authnRequest.getProtocolBinding())) { - //use AssertionConsumerServiceURL from request - - //check requested AssertionConsumingService URL against metadata - List<AssertionConsumerService> metadataAssertionServiceList = spSSODescriptor.getAssertionConsumerServices(); - for (AssertionConsumerService service : metadataAssertionServiceList) { - if (authnRequest.getProtocolBinding().equals(service.getBinding()) - && authnRequest.getAssertionConsumerServiceURL().equals(service.getLocation())) { - consumerService = SAML2Utils.createSAMLObject(AssertionConsumerService.class); - consumerService.setBinding(authnRequest.getProtocolBinding()); - consumerService.setLocation(authnRequest.getAssertionConsumerServiceURL()); - log.debug("Requested AssertionConsumerServiceURL is valid."); - } - } - - if (consumerService == null) { - throw new InvalidAssertionConsumerServiceException(authnRequest.getAssertionConsumerServiceURL()); - - } - - - } else { - //use AssertionConsumerServiceIndex and select consumerService from metadata - Integer aIdx = authnRequest.getAssertionConsumerServiceIndex(); - int assertionidx = 0; - - if(aIdx != null) { - assertionidx = aIdx.intValue(); - - } else { - assertionidx = SAML2Utils.getDefaultAssertionConsumerServiceIndex(spSSODescriptor); - - } - consumerService = spSSODescriptor.getAssertionConsumerServices().get(assertionidx); - - if (consumerService == null) { - throw new InvalidAssertionConsumerServiceException(aIdx); - - } - } - - - //validate AuthnRequest - AuthnRequest authReq = (AuthnRequest) samlReq; - String oaURL = moaRequest.getEntityMetadata(metadataProvider).getEntityID(); - log.info("Dispatch PVP2 AuthnRequest: OAURL=" + oaURL + " Binding=" + consumerService.getBinding()); - - pendingReq.setSPEntityId(StringEscapeUtils.escapeHtml(oaURL)); - pendingReq.setOnlineApplicationConfiguration(authConfig.getServiceProviderConfiguration(pendingReq.getSPEntityId())); - pendingReq.setBinding(consumerService.getBinding()); - pendingReq.setRequest(moaRequest); - pendingReq.setConsumerURL(consumerService.getLocation()); - - //parse AuthRequest - pendingReq.setPassiv(authReq.isPassive()); - pendingReq.setForce(authReq.isForceAuthn()); - - //AuthnRequest needs authentication - pendingReq.setNeedAuthentication(true); - - //set protocol action, which should be executed after authentication - pendingReq.setAction(AuthenticationAction.class.getName()); - - log.trace("Starting extended AuthnRequest validation and processing ... "); - authRequestValidator.validate(request, pendingReq, authReq, spSSODescriptor); - log.debug("Extended AuthnRequest validation and processing finished"); - - //write revisionslog entry - revisionsLogger.logEvent(pendingReq, PVPEventConstants.AUTHPROTOCOL_PVP_REQUEST_AUTHREQUEST, authReq.getID()); - - } - - @PostConstruct - private void verifyInitialization() { - if (pvpIDPCredentials == null) { - log.error("No SAML2 credentialProvider injected!"); - throw new RuntimeException("No SAML2 credentialProvider injected!"); - - } - } - -} diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AbstractPvp2XProtocol.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AbstractPvp2XProtocol.java new file mode 100644 index 00000000..3fac7894 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AbstractPvp2XProtocol.java @@ -0,0 +1,561 @@ +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 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: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * 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.egiz.eaaf.modules.pvp2.idp.impl; + +import java.util.List; +import javax.annotation.PostConstruct; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import at.gv.egiz.components.eventlog.api.EventConstants; +import at.gv.egiz.eaaf.core.api.IRequest; +import at.gv.egiz.eaaf.core.api.data.EAAFConstants; +import at.gv.egiz.eaaf.core.api.idp.IModulInfo; +import at.gv.egiz.eaaf.core.api.logging.IRevisionLogger; +import at.gv.egiz.eaaf.core.exceptions.AuthnRequestValidatorException; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.exceptions.InvalidProtocolRequestException; +import at.gv.egiz.eaaf.core.exceptions.NoPassivAuthenticationException; +import at.gv.egiz.eaaf.core.exceptions.SloException; +import at.gv.egiz.eaaf.core.impl.idp.controller.AbstractController; +import at.gv.egiz.eaaf.modules.pvp2.PvpEventConstants; +import at.gv.egiz.eaaf.modules.pvp2.api.IPvo2BasicConfiguration; +import at.gv.egiz.eaaf.modules.pvp2.api.binding.IEncoder; +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvpMetadataProvider; +import at.gv.egiz.eaaf.modules.pvp2.api.validation.IAuthnRequestValidator; +import at.gv.egiz.eaaf.modules.pvp2.exception.InvalidPvpRequestException; +import at.gv.egiz.eaaf.modules.pvp2.exception.NameIdFormatNotSupportedException; +import at.gv.egiz.eaaf.modules.pvp2.exception.NoMetadataInformationException; +import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2Exception; +import at.gv.egiz.eaaf.modules.pvp2.idp.exception.InvalidAssertionConsumerServiceException; +import at.gv.egiz.eaaf.modules.pvp2.impl.binding.PostBinding; +import at.gv.egiz.eaaf.modules.pvp2.impl.binding.RedirectBinding; +import at.gv.egiz.eaaf.modules.pvp2.impl.binding.SoapBinding; +import at.gv.egiz.eaaf.modules.pvp2.impl.message.InboundMessage; +import at.gv.egiz.eaaf.modules.pvp2.impl.message.PvpSProfileRequest; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.AbstractCredentialProvider; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; +import at.gv.egiz.eaaf.modules.pvp2.impl.validation.EaafUriCompare; +import at.gv.egiz.eaaf.modules.pvp2.impl.validation.TrustEngineFactory; +import at.gv.egiz.eaaf.modules.pvp2.impl.verification.SamlVerificationEngine; +import org.apache.commons.lang.StringEscapeUtils; +import org.apache.commons.lang3.StringUtils; +import org.joda.time.DateTime; +import org.opensaml.common.xml.SAMLConstants; +import org.opensaml.saml2.core.AuthnRequest; +import org.opensaml.saml2.core.Issuer; +import org.opensaml.saml2.core.NameIDType; +import org.opensaml.saml2.core.Response; +import org.opensaml.saml2.core.Status; +import org.opensaml.saml2.core.StatusCode; +import org.opensaml.saml2.core.StatusMessage; +import org.opensaml.saml2.metadata.AssertionConsumerService; +import org.opensaml.saml2.metadata.EntityDescriptor; +import org.opensaml.saml2.metadata.SPSSODescriptor; +import org.opensaml.ws.security.SecurityPolicyException; +import org.opensaml.xml.security.x509.X509Credential; +import org.opensaml.xml.signature.SignableXMLObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +public abstract class AbstractPvp2XProtocol extends AbstractController implements IModulInfo { + private static final Logger log = LoggerFactory.getLogger(AbstractPvp2XProtocol.class); + + @Autowired(required = true) + protected IPvo2BasicConfiguration pvpBasicConfiguration; + @Autowired(required = true) + protected IPvpMetadataProvider metadataProvider; + @Autowired(required = true) + protected SamlVerificationEngine samlVerificationEngine; + @Autowired(required = true) + protected IAuthnRequestValidator authRequestValidator; + + private AbstractCredentialProvider pvpIdpCredentials; + + + + /** + * Sets a specific credential provider for PVP S-Profile IDP component. + * + * @param pvpIdpCredentials credential provider + */ + public void setPvpIdpCredentials(final AbstractCredentialProvider pvpIdpCredentials) { + this.pvpIdpCredentials = pvpIdpCredentials; + + } + + @Override + public boolean generateErrorMessage(final Throwable e, final HttpServletRequest request, + final HttpServletResponse response, final IRequest protocolRequest) throws Throwable { + + if (protocolRequest == null) { + throw e; + } + + if (!(protocolRequest instanceof PvpSProfilePendingRequest)) { + throw e; + } + final PvpSProfilePendingRequest pvpRequest = (PvpSProfilePendingRequest) protocolRequest; + + final Response samlResponse = Saml2Utils.createSamlObject(Response.class); + final Status status = Saml2Utils.createSamlObject(Status.class); + final StatusCode statusCode = Saml2Utils.createSamlObject(StatusCode.class); + final StatusMessage statusMessage = Saml2Utils.createSamlObject(StatusMessage.class); + + String moaError = null; + + if (e instanceof NoPassivAuthenticationException) { + statusCode.setValue(StatusCode.NO_PASSIVE_URI); + statusMessage.setMessage(StringEscapeUtils.escapeXml(e.getLocalizedMessage())); + + } else if (e instanceof NameIdFormatNotSupportedException) { + statusCode.setValue(StatusCode.INVALID_NAMEID_POLICY_URI); + statusMessage.setMessage(StringEscapeUtils.escapeXml(e.getLocalizedMessage())); + + } else if (e instanceof SloException) { + // SLOExecpetions only occurs if session information is lost + return false; + + } else if (e instanceof Pvp2Exception) { + final Pvp2Exception ex = (Pvp2Exception) e; + statusCode.setValue(ex.getStatusCodeValue()); + final String statusMessageValue = ex.getStatusMessageValue(); + if (statusMessageValue != null) { + statusMessage.setMessage(StringEscapeUtils.escapeXml(statusMessageValue)); + } + moaError = statusMessager.mapInternalErrorToExternalError(ex.getErrorId()); + + } else { + statusCode.setValue(StatusCode.RESPONDER_URI); + statusMessage.setMessage(StringEscapeUtils.escapeXml(e.getLocalizedMessage())); + moaError = statusMessager.getResponseErrorCode(e); + } + + + if (StringUtils.isNotEmpty(moaError)) { + final StatusCode moaStatusCode = Saml2Utils.createSamlObject(StatusCode.class); + moaStatusCode.setValue(moaError); + statusCode.setStatusCode(moaStatusCode); + } + + status.setStatusCode(statusCode); + if (statusMessage.getMessage() != null) { + status.setStatusMessage(statusMessage); + } + samlResponse.setStatus(status); + final String remoteSessionID = Saml2Utils.getSecureIdentifier(); + samlResponse.setID(remoteSessionID); + + samlResponse.setIssueInstant(new DateTime()); + final Issuer nissuer = Saml2Utils.createSamlObject(Issuer.class); + nissuer.setValue(pvpBasicConfiguration.getIdpEntityId(pvpRequest.getAuthUrl())); + nissuer.setFormat(NameIDType.ENTITY); + samlResponse.setIssuer(nissuer); + + IEncoder encoder = null; + + if (pvpRequest.getBinding().equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI)) { + encoder = applicationContext.getBean("PVPRedirectBinding", RedirectBinding.class); + + } else if (pvpRequest.getBinding().equals(SAMLConstants.SAML2_POST_BINDING_URI)) { + encoder = applicationContext.getBean("PVPPOSTBinding", PostBinding.class); + + } else if (pvpRequest.getBinding().equals(SAMLConstants.SAML2_SOAP11_BINDING_URI)) { + encoder = applicationContext.getBean("PVPSOAPBinding", SoapBinding.class); + } + + if (encoder == null) { + // default to redirect binding + encoder = new RedirectBinding(); + } + + String relayState = null; + if (pvpRequest.getRequest() != null) { + relayState = pvpRequest.getRequest().getRelayState(); + } + + final X509Credential signCred = pvpIdpCredentials.getIdpAssertionSigningCredential(); + + encoder.encodeRespone(request, response, samlResponse, pvpRequest.getConsumerUrl(), relayState, + signCred, protocolRequest); + return true; + } + + @Override + public boolean validate(final HttpServletRequest request, final HttpServletResponse response, + final IRequest pending) { + + return true; + } + + protected void pvpMetadataRequest(final HttpServletRequest req, final HttpServletResponse resp) + throws EaafException { + // create pendingRequest object + final PvpSProfilePendingRequest pendingReq = + applicationContext.getBean(PvpSProfilePendingRequest.class); + pendingReq.initialize(req, authConfig); + pendingReq.setModule(getName()); + + revisionsLogger.logEvent(pendingReq.getUniqueSessionIdentifier(), + pendingReq.getUniqueTransactionIdentifier(), EventConstants.TRANSACTION_IP, + req.getRemoteAddr()); + + final MetadataAction metadataAction = applicationContext.getBean(MetadataAction.class); + metadataAction.processRequest(pendingReq, req, resp, null); + + } + + protected void pvpIdpPostRequest(final HttpServletRequest req, final HttpServletResponse resp) + throws EaafException { + PvpSProfilePendingRequest pendingReq = null; + + try { + // create pendingRequest object + pendingReq = applicationContext.getBean(PvpSProfilePendingRequest.class); + pendingReq.initialize(req, authConfig); + pendingReq.setModule(getName()); + + revisionsLogger.logEvent(EventConstants.SESSION_CREATED, + pendingReq.getUniqueSessionIdentifier()); + revisionsLogger.logEvent(EventConstants.TRANSACTION_CREATED, + pendingReq.getUniqueTransactionIdentifier()); + revisionsLogger.logEvent(pendingReq.getUniqueSessionIdentifier(), + pendingReq.getUniqueTransactionIdentifier(), EventConstants.TRANSACTION_IP, + req.getRemoteAddr()); + + // get POST-Binding decoder implementation + final InboundMessage msg = (InboundMessage) new PostBinding().decode(req, resp, + metadataProvider, false, + new EaafUriCompare(pvpBasicConfiguration.getIdpSsoPostService(pendingReq.getAuthUrl()))); + pendingReq.setRequest(msg); + + // preProcess Message + preProcess(req, resp, pendingReq); + + } catch (final SecurityPolicyException e) { + final String samlRequest = req.getParameter("SAMLRequest"); + log.warn("Receive INVALID protocol request: " + samlRequest, e); + + // write revision log entries + if (pendingReq != null) { + revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, + pendingReq.getUniqueTransactionIdentifier()); + } + + throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}); + + } catch (final SecurityException e) { + final String samlRequest = req.getParameter("SAMLRequest"); + log.warn("Receive INVALID protocol request: " + samlRequest, e); + + // write revision log entries + if (pendingReq != null) { + revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, + pendingReq.getUniqueTransactionIdentifier()); + } + + throw new InvalidProtocolRequestException("pvp2.22", new Object[] {e.getMessage()}); + + } catch (final EaafException e) { + + // write revision log entries + if (pendingReq != null) { + revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, + pendingReq.getUniqueTransactionIdentifier()); + } + + throw e; + + } catch (final Throwable e) { + final String samlRequest = req.getParameter("SAMLRequest"); + log.warn("Receive INVALID protocol request: " + samlRequest, e); + + // write revision log entries + if (pendingReq != null) { + revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, + pendingReq.getUniqueTransactionIdentifier()); + } + + throw new EaafException("pvp2.24", new Object[] {e.getMessage()}, e); + } + } + + protected void pvpIdpRedirecttRequest(final HttpServletRequest req, + final HttpServletResponse resp) throws EaafException { + PvpSProfilePendingRequest pendingReq = null; + try { + // create pendingRequest object + pendingReq = applicationContext.getBean(PvpSProfilePendingRequest.class); + pendingReq.initialize(req, authConfig); + pendingReq.setModule(getName()); + + revisionsLogger.logEvent(EventConstants.SESSION_CREATED, + pendingReq.getUniqueSessionIdentifier()); + revisionsLogger.logEvent(EventConstants.TRANSACTION_CREATED, + pendingReq.getUniqueTransactionIdentifier()); + revisionsLogger.logEvent(pendingReq.getUniqueSessionIdentifier(), + pendingReq.getUniqueTransactionIdentifier(), EventConstants.TRANSACTION_IP, + req.getRemoteAddr()); + + // get POST-Binding decoder implementation + final InboundMessage msg = (InboundMessage) new RedirectBinding().decode(req, resp, + metadataProvider, false, new EaafUriCompare( + pvpBasicConfiguration.getIdpSsoRedirectService(pendingReq.getAuthUrl()))); + pendingReq.setRequest(msg); + + // preProcess Message + preProcess(req, resp, pendingReq); + + } catch (final SecurityPolicyException e) { + final String samlRequest = req.getParameter("SAMLRequest"); + log.warn("Receive INVALID protocol request: " + samlRequest, e); + + // write revision log entries + if (pendingReq != null) { + revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, + pendingReq.getUniqueTransactionIdentifier()); + } + + throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}); + + } catch (final SecurityException e) { + final String samlRequest = req.getParameter("SAMLRequest"); + log.warn("Receive INVALID protocol request: " + samlRequest, e); + + // write revision log entries + if (pendingReq != null) { + revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, + pendingReq.getUniqueTransactionIdentifier()); + } + + throw new InvalidProtocolRequestException("pvp2.22", new Object[] {e.getMessage()}); + + } catch (final EaafException e) { + final String samlRequest = req.getParameter("SAMLRequest"); + log.info("Receive INVALID protocol request: " + samlRequest); + + // write revision log entries + if (pendingReq != null) { + revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, + pendingReq.getUniqueTransactionIdentifier()); + } + + throw e; + + } catch (final Throwable e) { + final String samlRequest = req.getParameter("SAMLRequest"); + log.warn("Receive INVALID protocol request: " + samlRequest, e); + + // write revision log entries + if (pendingReq != null) { + revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, + pendingReq.getUniqueTransactionIdentifier()); + } + + throw new EaafException("pvp2.24", new Object[] {e.getMessage()}, e); + } + } + + + + /** + * Authentication request pre-processor. + * + * @param request http request + * @param response http response + * @param pendingReq current pending request + * @return true if preprocess can handle this request type, otherwise false + * @throws Throwable In case of an error + */ + protected abstract boolean childPreProcess(HttpServletRequest request, + HttpServletResponse response, PvpSProfilePendingRequest pendingReq) throws Throwable; + + protected void preProcess(final HttpServletRequest request, final HttpServletResponse response, + final PvpSProfilePendingRequest pendingReq) throws Throwable { + + final InboundMessage msg = pendingReq.getRequest(); + + if (StringUtils.isEmpty(msg.getEntityID())) { + throw new InvalidProtocolRequestException("pvp2.20", new Object[] {}); + + } + + if (!msg.isVerified()) { + samlVerificationEngine.verify(msg, + TrustEngineFactory.getSignatureKnownKeysTrustEngine(metadataProvider)); + msg.setVerified(true); + + } + + revisionsLogger.logEvent(pendingReq, IRevisionLogger.AUTHPROTOCOL_TYPE, + getAuthProtocolIdentifier()); + + if (msg instanceof PvpSProfileRequest + && ((PvpSProfileRequest) msg).getSamlRequest() instanceof AuthnRequest) { + preProcessAuthRequest(request, response, pendingReq); + } else if (childPreProcess(request, response, pendingReq)) { + log.debug("Find protocol handler in child implementation"); + } else { + log.error("Receive unsupported PVP21 message of type: " + + ((PvpSProfileRequest) msg).getSamlRequest().getClass().getName()); + throw new InvalidPvpRequestException("pvp2.09", + new Object[] {((PvpSProfileRequest) msg).getSamlRequest().getClass().getName()}); + } + + + + // switch to session authentication + protAuthService.performAuthentication(request, response, pendingReq); + } + + + /** + * PreProcess Authn request. + * + * @param request http request + * @param response http response + * @param pendingReq current pending request + * @throws Throwable in case of an error + */ + private void preProcessAuthRequest(final HttpServletRequest request, + final HttpServletResponse response, final PvpSProfilePendingRequest pendingReq) + throws Throwable { + + final PvpSProfileRequest moaRequest = ((PvpSProfileRequest) pendingReq.getRequest()); + final SignableXMLObject samlReq = moaRequest.getSamlRequest(); + + if (!(samlReq instanceof AuthnRequest)) { + throw new InvalidPvpRequestException("Unsupported request", new Object[] {}); + } + + final EntityDescriptor metadata = moaRequest.getEntityMetadata(metadataProvider); + if (metadata == null) { + throw new NoMetadataInformationException(); + } + final SPSSODescriptor spSsoDescriptor = metadata.getSPSSODescriptor(SAMLConstants.SAML20P_NS); + + final AuthnRequest authnRequest = (AuthnRequest) samlReq; + + if (authnRequest.getIssueInstant() == null) { + log.warn("Unsupported request: No IssueInstant Attribute found."); + throw new AuthnRequestValidatorException("pvp2.22", + new Object[] {"Unsupported request: No IssueInstant Attribute found"}, pendingReq); + + } + + if (authnRequest.getIssueInstant().minusMinutes(EAAFConstants.ALLOWED_TIME_JITTER) + .isAfterNow()) { + log.warn("Unsupported request: No IssueInstant DateTime is not valid anymore."); + throw new AuthnRequestValidatorException("pvp2.22", + new Object[] {"Unsupported request: No IssueInstant DateTime is not valid anymore."}, + pendingReq); + + } + + // parse AssertionConsumerService + AssertionConsumerService consumerService = null; + if (StringUtils.isNotEmpty(authnRequest.getAssertionConsumerServiceURL()) + && StringUtils.isNotEmpty(authnRequest.getProtocolBinding())) { + // use AssertionConsumerServiceURL from request + + // check requested AssertionConsumingService URL against metadata + final List<AssertionConsumerService> metadataAssertionServiceList = + spSsoDescriptor.getAssertionConsumerServices(); + for (final AssertionConsumerService service : metadataAssertionServiceList) { + if (authnRequest.getProtocolBinding().equals(service.getBinding()) + && authnRequest.getAssertionConsumerServiceURL().equals(service.getLocation())) { + consumerService = Saml2Utils.createSamlObject(AssertionConsumerService.class); + consumerService.setBinding(authnRequest.getProtocolBinding()); + consumerService.setLocation(authnRequest.getAssertionConsumerServiceURL()); + log.debug("Requested AssertionConsumerServiceURL is valid."); + } + } + + if (consumerService == null) { + throw new InvalidAssertionConsumerServiceException( + authnRequest.getAssertionConsumerServiceURL()); + + } + + + } else { + // use AssertionConsumerServiceIndex and select consumerService from metadata + final Integer aIdx = authnRequest.getAssertionConsumerServiceIndex(); + int assertionidx = 0; + + if (aIdx != null) { + assertionidx = aIdx.intValue(); + + } else { + assertionidx = Saml2Utils.getDefaultAssertionConsumerServiceIndex(spSsoDescriptor); + + } + consumerService = spSsoDescriptor.getAssertionConsumerServices().get(assertionidx); + + if (consumerService == null) { + throw new InvalidAssertionConsumerServiceException(aIdx); + + } + } + + + // validate AuthnRequest + final AuthnRequest authReq = (AuthnRequest) samlReq; + final String oaUrl = moaRequest.getEntityMetadata(metadataProvider).getEntityID(); + log.info( + "Dispatch PVP2 AuthnRequest: OAURL=" + oaUrl + " Binding=" + consumerService.getBinding()); + + pendingReq.setSpEntityId(StringEscapeUtils.escapeHtml(oaUrl)); + pendingReq.setOnlineApplicationConfiguration( + authConfig.getServiceProviderConfiguration(pendingReq.getSpEntityId())); + pendingReq.setBinding(consumerService.getBinding()); + pendingReq.setRequest(moaRequest); + pendingReq.setConsumerUrl(consumerService.getLocation()); + + // parse AuthRequest + pendingReq.setPassiv(authReq.isPassive()); + pendingReq.setForce(authReq.isForceAuthn()); + + // AuthnRequest needs authentication + pendingReq.setNeedAuthentication(true); + + // set protocol action, which should be executed after authentication + pendingReq.setAction(AuthenticationAction.class.getName()); + + log.trace("Starting extended AuthnRequest validation and processing ... "); + authRequestValidator.validate(request, pendingReq, authReq, spSsoDescriptor); + log.debug("Extended AuthnRequest validation and processing finished"); + + // write revisionslog entry + revisionsLogger.logEvent(pendingReq, PvpEventConstants.AUTHPROTOCOL_PVP_REQUEST_AUTHREQUEST, + authReq.getID()); + + } + + @PostConstruct + private void verifyInitialization() { + if (pvpIdpCredentials == null) { + log.error("No SAML2 credentialProvider injected!"); + throw new RuntimeException("No SAML2 credentialProvider injected!"); + + } + } + +} diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AuthenticationAction.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AuthenticationAction.java index cbbed659..9378b579 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AuthenticationAction.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AuthenticationAction.java @@ -1,35 +1,47 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. * - * Licensed under the EUPL, Version 1.2 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: + * Licensed under the EUPL, Version 1.2 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: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * - * 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. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ + * 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.egiz.eaaf.modules.pvp2.idp.impl; import javax.annotation.PostConstruct; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; - +import at.gv.egiz.eaaf.core.api.IRequest; +import at.gv.egiz.eaaf.core.api.idp.IAction; +import at.gv.egiz.eaaf.core.api.idp.IAuthData; +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import at.gv.egiz.eaaf.core.api.idp.slo.SloInformationInterface; +import at.gv.egiz.eaaf.core.api.logging.IRevisionLogger; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.impl.data.SLOInformationImpl; +import at.gv.egiz.eaaf.modules.pvp2.api.IPvo2BasicConfiguration; +import at.gv.egiz.eaaf.modules.pvp2.api.binding.IEncoder; +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvpMetadataProvider; +import at.gv.egiz.eaaf.modules.pvp2.exception.BindingNotSupportedException; +import at.gv.egiz.eaaf.modules.pvp2.idp.exception.ResponderErrorException; +import at.gv.egiz.eaaf.modules.pvp2.idp.impl.builder.AuthResponseBuilder; +import at.gv.egiz.eaaf.modules.pvp2.idp.impl.builder.Pvp2AssertionBuilder; +import at.gv.egiz.eaaf.modules.pvp2.impl.binding.PostBinding; +import at.gv.egiz.eaaf.modules.pvp2.impl.binding.RedirectBinding; +import at.gv.egiz.eaaf.modules.pvp2.impl.message.PvpSProfileRequest; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.AbstractCredentialProvider; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; import org.joda.time.DateTime; import org.opensaml.common.xml.SAMLConstants; import org.opensaml.saml2.core.Assertion; @@ -45,141 +57,125 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Service; -import at.gv.egiz.eaaf.core.api.IRequest; -import at.gv.egiz.eaaf.core.api.idp.IAction; -import at.gv.egiz.eaaf.core.api.idp.IAuthData; -import at.gv.egiz.eaaf.core.api.idp.IConfiguration; -import at.gv.egiz.eaaf.core.api.idp.slo.SLOInformationInterface; -import at.gv.egiz.eaaf.core.api.logging.IRevisionLogger; -import at.gv.egiz.eaaf.core.exceptions.EAAFException; -import at.gv.egiz.eaaf.core.impl.data.SLOInformationImpl; -import at.gv.egiz.eaaf.modules.pvp2.api.IPVP2BasicConfiguration; -import at.gv.egiz.eaaf.modules.pvp2.api.binding.IEncoder; -import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPVPMetadataProvider; -import at.gv.egiz.eaaf.modules.pvp2.exception.BindingNotSupportedException; -import at.gv.egiz.eaaf.modules.pvp2.idp.exception.ResponderErrorException; -import at.gv.egiz.eaaf.modules.pvp2.idp.impl.builder.AuthResponseBuilder; -import at.gv.egiz.eaaf.modules.pvp2.idp.impl.builder.PVP2AssertionBuilder; -import at.gv.egiz.eaaf.modules.pvp2.impl.binding.PostBinding; -import at.gv.egiz.eaaf.modules.pvp2.impl.binding.RedirectBinding; -import at.gv.egiz.eaaf.modules.pvp2.impl.message.PVPSProfileRequest; -import at.gv.egiz.eaaf.modules.pvp2.impl.utils.AbstractCredentialProvider; -import at.gv.egiz.eaaf.modules.pvp2.impl.utils.SAML2Utils; - @Service("PVPAuthenticationRequestAction") public class AuthenticationAction implements IAction { - private static final Logger log = LoggerFactory.getLogger(AuthenticationAction.class); - - private static final String CONFIG_PROPERTY_PVP2_ENABLE_ENCRYPTION = "protocols.pvp2.assertion.encryption.active"; - - @Autowired(required=true) private IPVPMetadataProvider metadataProvider; - @Autowired(required=true) ApplicationContext springContext; - @Autowired(required=true) IConfiguration authConfig; - @Autowired(required=true) PVP2AssertionBuilder assertionBuilder; - @Autowired(required=true) IPVP2BasicConfiguration pvpBasicConfiguration; - @Autowired(required=true) IRevisionLogger revisionsLogger; - - private AbstractCredentialProvider pvpIDPCredentials; - - /** - * Sets a specific credential provider for PVP S-Profile IDP component. - * @param pvpIDPCredentials credential provider - */ - public void setPvpIDPCredentials(AbstractCredentialProvider pvpIDPCredentials) { - this.pvpIDPCredentials = pvpIDPCredentials; - - } - - @Override - public SLOInformationInterface processRequest(IRequest req, HttpServletRequest httpReq, - HttpServletResponse httpResp, IAuthData authData) throws ResponderErrorException { - final PVPSProfilePendingRequest pvpRequest = (PVPSProfilePendingRequest) req; - try { - //get basic information - final PVPSProfileRequest moaRequest = (PVPSProfileRequest) pvpRequest.getRequest(); - final AuthnRequest authnRequest = (AuthnRequest) moaRequest.getSamlRequest(); - final EntityDescriptor peerEntity = moaRequest.getEntityMetadata(metadataProvider); - - final AssertionConsumerService consumerService = - SAML2Utils.createSAMLObject(AssertionConsumerService.class); - consumerService.setBinding(pvpRequest.getBinding()); - consumerService.setLocation(pvpRequest.getConsumerURL()); - - final DateTime date = new DateTime(); - final SLOInformationImpl sloInformation = new SLOInformationImpl(); - final String issuerEntityID = pvpBasicConfiguration.getIDPEntityId(pvpRequest.getAuthURL()); - - //build Assertion - final Assertion assertion = assertionBuilder.buildAssertion(issuerEntityID, pvpRequest, authnRequest, authData, - peerEntity, date, consumerService, sloInformation); - - final Response authResponse = AuthResponseBuilder.buildResponse( - metadataProvider, issuerEntityID, authnRequest, - date, assertion, authConfig.getBasicConfigurationBoolean( - CONFIG_PROPERTY_PVP2_ENABLE_ENCRYPTION, true)); - - IEncoder binding = null; - - if (consumerService.getBinding().equals( - SAMLConstants.SAML2_REDIRECT_BINDING_URI)) { - binding = springContext.getBean("PVPRedirectBinding", RedirectBinding.class); - - } else if (consumerService.getBinding().equals( - SAMLConstants.SAML2_POST_BINDING_URI)) { - binding = springContext.getBean("PVPPOSTBinding", PostBinding.class); - - } - - if (binding == null) { - throw new BindingNotSupportedException(consumerService.getBinding()); - } - - binding.encodeRespone(httpReq, httpResp, authResponse, - consumerService.getLocation(), moaRequest.getRelayState(), - pvpIDPCredentials.getIDPAssertionSigningCredential(), req); - - revisionsLogger.logEvent(req, 3105, authResponse.getID()); - - //set protocol type - sloInformation.setProtocolType(req.requestedModule()); - sloInformation.setSpEntityID(req.getServiceProviderConfiguration().getUniqueIdentifier()); - return sloInformation; - - } catch (MessageEncodingException | SecurityException e) { - log.warn("Message Encoding exception", e); - throw new ResponderErrorException("pvp2.01", null, e); - - } catch (final EAAFException e) { - log.info("Response generation error: Msg: ", e.getMessage()); - throw new ResponderErrorException(e.getErrorId(), e.getParams(), e); - - } catch (final Exception e) { - log.warn("Response generation error", e); - throw new ResponderErrorException("pvp2.01", null, e); - - } - - } - - @Override - public boolean needAuthentication(IRequest req, HttpServletRequest httpReq, - HttpServletResponse httpResp) { - return true; - } - - @Override - public String getDefaultActionName() { - return "PVPAuthenticationRequestAction"; - - } - - @PostConstruct - private void verifyInitialization() { - if (pvpIDPCredentials == null) { - log.error("No SAML2 credentialProvider injected!"); - throw new RuntimeException("No SAML2 credentialProvider injected!"); - - } - } + private static final Logger log = LoggerFactory.getLogger(AuthenticationAction.class); + + private static final String CONFIG_PROPERTY_PVP2_ENABLE_ENCRYPTION = + "protocols.pvp2.assertion.encryption.active"; + + @Autowired(required = true) + private IPvpMetadataProvider metadataProvider; + @Autowired(required = true) + ApplicationContext springContext; + @Autowired(required = true) + IConfiguration authConfig; + @Autowired(required = true) + Pvp2AssertionBuilder assertionBuilder; + @Autowired(required = true) + IPvo2BasicConfiguration pvpBasicConfiguration; + @Autowired(required = true) + IRevisionLogger revisionsLogger; + + private AbstractCredentialProvider pvpIdpCredentials; + + /** + * Sets a specific credential provider for PVP S-Profile IDP component. + * + * @param pvpIdpCredentials credential provider + */ + public void setPvpIdpCredentials(final AbstractCredentialProvider pvpIdpCredentials) { + this.pvpIdpCredentials = pvpIdpCredentials; + + } + + @Override + public SloInformationInterface processRequest(final IRequest req, + final HttpServletRequest httpReq, final HttpServletResponse httpResp, + final IAuthData authData) throws ResponderErrorException { + final PvpSProfilePendingRequest pvpRequest = (PvpSProfilePendingRequest) req; + try { + // get basic information + final PvpSProfileRequest moaRequest = (PvpSProfileRequest) pvpRequest.getRequest(); + final AuthnRequest authnRequest = (AuthnRequest) moaRequest.getSamlRequest(); + final EntityDescriptor peerEntity = moaRequest.getEntityMetadata(metadataProvider); + + final AssertionConsumerService consumerService = + Saml2Utils.createSamlObject(AssertionConsumerService.class); + consumerService.setBinding(pvpRequest.getBinding()); + consumerService.setLocation(pvpRequest.getConsumerUrl()); + + final DateTime date = new DateTime(); + final SLOInformationImpl sloInformation = new SLOInformationImpl(); + final String issuerEntityID = pvpBasicConfiguration.getIdpEntityId(pvpRequest.getAuthUrl()); + + // build Assertion + final Assertion assertion = assertionBuilder.buildAssertion(issuerEntityID, pvpRequest, + authnRequest, authData, peerEntity, date, consumerService, sloInformation); + + final Response authResponse = AuthResponseBuilder.buildResponse(metadataProvider, + issuerEntityID, authnRequest, date, assertion, + authConfig.getBasicConfigurationBoolean(CONFIG_PROPERTY_PVP2_ENABLE_ENCRYPTION, true)); + + IEncoder binding = null; + + if (consumerService.getBinding().equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI)) { + binding = springContext.getBean("PVPRedirectBinding", RedirectBinding.class); + + } else if (consumerService.getBinding().equals(SAMLConstants.SAML2_POST_BINDING_URI)) { + binding = springContext.getBean("PVPPOSTBinding", PostBinding.class); + + } + + if (binding == null) { + throw new BindingNotSupportedException(consumerService.getBinding()); + } + + binding.encodeRespone(httpReq, httpResp, authResponse, consumerService.getLocation(), + moaRequest.getRelayState(), pvpIdpCredentials.getIdpAssertionSigningCredential(), req); + + revisionsLogger.logEvent(req, 3105, authResponse.getID()); + + // set protocol type + sloInformation.setProtocolType(req.requestedModule()); + sloInformation.setSpEntityID(req.getServiceProviderConfiguration().getUniqueIdentifier()); + return sloInformation; + + } catch (MessageEncodingException | SecurityException e) { + log.warn("Message Encoding exception", e); + throw new ResponderErrorException("pvp2.01", null, e); + + } catch (final EaafException e) { + log.info("Response generation error: Msg: ", e.getMessage()); + throw new ResponderErrorException(e.getErrorId(), e.getParams(), e); + + } catch (final Exception e) { + log.warn("Response generation error", e); + throw new ResponderErrorException("pvp2.01", null, e); + + } + + } + + @Override + public boolean needAuthentication(final IRequest req, final HttpServletRequest httpReq, + final HttpServletResponse httpResp) { + return true; + } + + @Override + public String getDefaultActionName() { + return "PVPAuthenticationRequestAction"; + + } + + @PostConstruct + private void verifyInitialization() { + if (pvpIdpCredentials == null) { + log.error("No SAML2 credentialProvider injected!"); + throw new RuntimeException("No SAML2 credentialProvider injected!"); + + } + } } diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/MetadataAction.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/MetadataAction.java index 6b957522..a1e8b5ba 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/MetadataAction.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/MetadataAction.java @@ -1,123 +1,121 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. * - * Licensed under the EUPL, Version 1.2 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: + * Licensed under the EUPL, Version 1.2 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: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * - * 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. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ + * 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.egiz.eaaf.modules.pvp2.idp.impl; import javax.annotation.PostConstruct; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.MediaType; -import org.springframework.stereotype.Service; - import at.gv.egiz.eaaf.core.api.IRequest; import at.gv.egiz.eaaf.core.api.idp.IAction; import at.gv.egiz.eaaf.core.api.idp.IAuthData; -import at.gv.egiz.eaaf.core.api.idp.slo.SLOInformationInterface; +import at.gv.egiz.eaaf.core.api.idp.slo.SloInformationInterface; import at.gv.egiz.eaaf.core.api.logging.IRevisionLogger; -import at.gv.egiz.eaaf.modules.pvp2.PVPEventConstants; -import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPVPMetadataBuilderConfiguration; -import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPVPMetadataConfigurationFactory; -import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2MetadataException; -import at.gv.egiz.eaaf.modules.pvp2.impl.builder.PVPMetadataBuilder; +import at.gv.egiz.eaaf.modules.pvp2.PvpEventConstants; +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvpMetadataBuilderConfiguration; +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvpMetadataConfigurationFactory; +import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2MetadataException; +import at.gv.egiz.eaaf.modules.pvp2.impl.builder.PvpMetadataBuilder; import at.gv.egiz.eaaf.modules.pvp2.impl.utils.AbstractCredentialProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Service; @Service("pvpMetadataService") public class MetadataAction implements IAction { - private static final Logger log = LoggerFactory.getLogger(MetadataAction.class); - - @Autowired private IRevisionLogger revisionsLogger; - @Autowired private PVPMetadataBuilder metadatabuilder; - @Autowired private IPVPMetadataConfigurationFactory configFactory; - - private AbstractCredentialProvider pvpIDPCredentials; - - /** - * Sets a specific credential provider for PVP S-Profile IDP component. - * @param pvpIDPCredentials credential provider - */ - public void setPvpIDPCredentials(AbstractCredentialProvider pvpIDPCredentials) { - this.pvpIDPCredentials = pvpIDPCredentials; - - } - - public SLOInformationInterface processRequest(IRequest req, HttpServletRequest httpReq, - HttpServletResponse httpResp, IAuthData authData) throws PVP2MetadataException { - try { - revisionsLogger.logEvent(req, PVPEventConstants.AUTHPROTOCOL_PVP_METADATA); - - //build metadata - IPVPMetadataBuilderConfiguration metadataConfig = - configFactory.generateMetadataBuilderConfiguration( - req.getAuthURLWithOutSlash(), - pvpIDPCredentials); - - ; - - String metadataXML = metadatabuilder.buildPVPMetadata(metadataConfig); - log.debug("METADATA: " + metadataXML); - - byte[] content = metadataXML.getBytes("UTF-8"); - httpResp.setStatus(HttpServletResponse.SC_OK); - httpResp.setContentLength(content.length); - httpResp.setContentType(MediaType.APPLICATION_XML_VALUE); - httpResp.getOutputStream().write(content); - return null; - - } catch (Exception e) { - log.error("Failed to generate metadata", e); - throw new PVP2MetadataException("pvp2.27", null); - } - } - - public boolean needAuthentication(IRequest req, HttpServletRequest httpReq, - HttpServletResponse httpResp) { - return false; - } - - /* (non-Javadoc) - * @see at.gv.egovernment.moa.id.moduls.IAction#getDefaultActionName() - */ - @Override - public String getDefaultActionName() { - return "IDP - PVP Metadata action"; - } - - @PostConstruct - private void verifyInitialization() { - if (pvpIDPCredentials == null) { - log.error("No SAML2 credentialProvider injected!"); - throw new RuntimeException("No SAML2 credentialProvider injected!"); - - } - } - + private static final Logger log = LoggerFactory.getLogger(MetadataAction.class); + + @Autowired + private IRevisionLogger revisionsLogger; + @Autowired + private PvpMetadataBuilder metadatabuilder; + @Autowired + private IPvpMetadataConfigurationFactory configFactory; + + private AbstractCredentialProvider pvpIdpCredentials; + + /** + * Sets a specific credential provider for PVP S-Profile IDP component. + * + * @param pvpIdpCredentials credential provider + */ + public void setPvpIdpCredentials(final AbstractCredentialProvider pvpIdpCredentials) { + this.pvpIdpCredentials = pvpIdpCredentials; + + } + + @Override + public SloInformationInterface processRequest(final IRequest req, + final HttpServletRequest httpReq, final HttpServletResponse httpResp, + final IAuthData authData) throws Pvp2MetadataException { + try { + revisionsLogger.logEvent(req, PvpEventConstants.AUTHPROTOCOL_PVP_METADATA); + + // build metadata + final IPvpMetadataBuilderConfiguration metadataConfig = configFactory + .generateMetadataBuilderConfiguration(req.getAuthUrlWithOutSlash(), pvpIdpCredentials); + + + + final String metadataXml = metadatabuilder.buildPvpMetadata(metadataConfig); + log.trace("METADATA: " + metadataXml); + + final byte[] content = metadataXml.getBytes("UTF-8"); + httpResp.setStatus(HttpServletResponse.SC_OK); + httpResp.setContentLength(content.length); + httpResp.setContentType(MediaType.APPLICATION_XML_VALUE); + httpResp.getOutputStream().write(content); + return null; + + } catch (final Exception e) { + log.error("Failed to generate metadata", e); + throw new Pvp2MetadataException("pvp2.27", null); + } + } + + @Override + public boolean needAuthentication(final IRequest req, final HttpServletRequest httpReq, + final HttpServletResponse httpResp) { + return false; + } + + /* + * (non-Javadoc) + * + * @see at.gv.egovernment.moa.id.moduls.IAction#getDefaultActionName() + */ + @Override + public String getDefaultActionName() { + return "IDP - PVP Metadata action"; + } + + @PostConstruct + private void verifyInitialization() { + if (pvpIdpCredentials == null) { + log.error("No SAML2 credentialProvider injected!"); + throw new RuntimeException("No SAML2 credentialProvider injected!"); + + } + } + } diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/PVPSProfilePendingRequest.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/PVPSProfilePendingRequest.java deleted file mode 100644 index 7f086ff6..00000000 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/PVPSProfilePendingRequest.java +++ /dev/null @@ -1,69 +0,0 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. - * - * Licensed under the EUPL, Version 1.2 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: - * https://joinup.ec.europa.eu/news/understanding-eupl-v12 - * - * 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.egiz.eaaf.modules.pvp2.idp.impl; - -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.context.annotation.Scope; -import org.springframework.stereotype.Component; - -import at.gv.egiz.eaaf.core.impl.idp.controller.protocols.RequestImpl; -import at.gv.egiz.eaaf.modules.pvp2.impl.message.InboundMessage; - -@Component("PVPSProfilePendingRequest") -@Scope(value = BeanDefinition.SCOPE_PROTOTYPE) -public class PVPSProfilePendingRequest extends RequestImpl { - private static final long serialVersionUID = 4889919265919638188L; - - InboundMessage request; - String binding; - String consumerURL; - - public InboundMessage getRequest() { - return request; - } - - public void setRequest(InboundMessage request) { - this.request = request; - } - - public String getBinding() { - return binding; - } - - public void setBinding(String binding) { - this.binding = binding; - } - - public String getConsumerURL() { - return consumerURL; - } - - public void setConsumerURL(String consumerURL) { - this.consumerURL = consumerURL; - - } -} diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/PvpSProfilePendingRequest.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/PvpSProfilePendingRequest.java new file mode 100644 index 00000000..6c621841 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/PvpSProfilePendingRequest.java @@ -0,0 +1,61 @@ +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 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: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * 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.egiz.eaaf.modules.pvp2.idp.impl; + +import at.gv.egiz.eaaf.core.impl.idp.controller.protocols.RequestImpl; +import at.gv.egiz.eaaf.modules.pvp2.impl.message.InboundMessage; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +@Component("PVPSProfilePendingRequest") +@Scope(value = BeanDefinition.SCOPE_PROTOTYPE) +public class PvpSProfilePendingRequest extends RequestImpl { + private static final long serialVersionUID = 4889919265919638188L; + + InboundMessage request; + String binding; + String consumerUrl; + + public InboundMessage getRequest() { + return request; + } + + public void setRequest(final InboundMessage request) { + this.request = request; + } + + public String getBinding() { + return binding; + } + + public void setBinding(final String binding) { + this.binding = binding; + } + + public String getConsumerUrl() { + return consumerUrl; + } + + public void setConsumerUrl(final String consumerUrl) { + this.consumerUrl = consumerUrl; + + } +} diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/AuthResponseBuilder.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/AuthResponseBuilder.java index 07423c19..bf51ac0f 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/AuthResponseBuilder.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/AuthResponseBuilder.java @@ -1,41 +1,35 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. * - * Licensed under the EUPL, Version 1.2 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: + * Licensed under the EUPL, Version 1.2 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: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * - * 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. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ + * 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.egiz.eaaf.modules.pvp2.idp.impl.builder; import java.util.ArrayList; import java.util.List; - +import at.gv.egiz.eaaf.modules.pvp2.PvpConstants; +import at.gv.egiz.eaaf.modules.pvp2.idp.exception.InvalidAssertionEncryptionException; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; import org.joda.time.DateTime; -import org.opensaml.Configuration; import org.opensaml.common.xml.SAMLConstants; import org.opensaml.saml2.core.Assertion; import org.opensaml.saml2.core.EncryptedAssertion; import org.opensaml.saml2.core.Issuer; -import org.opensaml.saml2.core.NameID; +import org.opensaml.saml2.core.NameIDType; import org.opensaml.saml2.core.RequestAbstractType; import org.opensaml.saml2.core.Response; import org.opensaml.saml2.encryption.Encrypter; @@ -57,97 +51,111 @@ import org.opensaml.xml.security.x509.X509Credential; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import at.gv.egiz.eaaf.modules.pvp2.PVPConstants; -import at.gv.egiz.eaaf.modules.pvp2.idp.exception.InvalidAssertionEncryptionException; -import at.gv.egiz.eaaf.modules.pvp2.impl.utils.SAML2Utils; - /** + * Authentication response builder. + * * @author tlenz * */ public class AuthResponseBuilder { - private static final Logger log = LoggerFactory.getLogger(AuthResponseBuilder.class); - - public static Response buildResponse(MetadataProvider metadataProvider, String issuerEntityID, RequestAbstractType req, DateTime date, Assertion assertion, boolean enableEncryption) throws InvalidAssertionEncryptionException { - Response authResponse = SAML2Utils.createSAMLObject(Response.class); - - Issuer nissuer = SAML2Utils.createSAMLObject(Issuer.class); - - nissuer.setValue(issuerEntityID); - nissuer.setFormat(NameID.ENTITY); - authResponse.setIssuer(nissuer); - authResponse.setInResponseTo(req.getID()); - - //set responseID - String remoteSessionID = SAML2Utils.getSecureIdentifier(); - authResponse.setID(remoteSessionID); - - - //SAML2 response required IssueInstant - authResponse.setIssueInstant(date); - - authResponse.setStatus(SAML2Utils.getSuccessStatus()); - - //check, if metadata includes an encryption key - MetadataCredentialResolver mdCredResolver = - new MetadataCredentialResolver(metadataProvider); - - CriteriaSet criteriaSet = new CriteriaSet(); - criteriaSet.add( new EntityIDCriteria(req.getIssuer().getValue()) ); - criteriaSet.add( new MetadataCriteria(SPSSODescriptor.DEFAULT_ELEMENT_NAME, SAMLConstants.SAML20P_NS) ); - criteriaSet.add( new UsageCriteria(UsageType.ENCRYPTION) ); - - X509Credential encryptionCredentials = null; - try { - encryptionCredentials = (X509Credential) mdCredResolver.resolveSingle(criteriaSet); - - } catch (SecurityException e2) { - log.warn("Can not extract the Assertion Encryption-Key from metadata", e2); - throw new InvalidAssertionEncryptionException(); - - } - - if (encryptionCredentials != null && enableEncryption) { - //encrypt SAML2 assertion - - try { - - EncryptionParameters dataEncParams = new EncryptionParameters(); - dataEncParams.setAlgorithm(PVPConstants.DEFAULT_SYM_ENCRYPTION_METHODE); - - List<KeyEncryptionParameters> keyEncParamList = new ArrayList<KeyEncryptionParameters>(); - KeyEncryptionParameters keyEncParam = new KeyEncryptionParameters(); - - keyEncParam.setEncryptionCredential(encryptionCredentials); - keyEncParam.setAlgorithm(PVPConstants.DEFAULT_ASYM_ENCRYPTION_METHODE); - KeyInfoGeneratorFactory kigf = Configuration.getGlobalSecurityConfiguration() - .getKeyInfoGeneratorManager().getDefaultManager() - .getFactory(encryptionCredentials); - keyEncParam.setKeyInfoGenerator(kigf.newInstance()); - keyEncParamList.add(keyEncParam); - - Encrypter samlEncrypter = new Encrypter(dataEncParams, keyEncParamList); - //samlEncrypter.setKeyPlacement(KeyPlacement.INLINE); - samlEncrypter.setKeyPlacement(KeyPlacement.PEER); - - EncryptedAssertion encryptAssertion = null; - - encryptAssertion = samlEncrypter.encrypt(assertion); - - authResponse.getEncryptedAssertions().add(encryptAssertion); - - } catch (EncryptionException e1) { - log.warn("Can not encrypt the PVP2 assertion", e1); - throw new InvalidAssertionEncryptionException(); - - } - - } else { - authResponse.getAssertions().add(assertion); - - } - - return authResponse; - } + private static final Logger log = LoggerFactory.getLogger(AuthResponseBuilder.class); + + /** + * Build PVP2 S-Profile authentication response. + * + * @param metadataProvider Service-Provider metadata + * @param issuerEntityID IDP entityId + * @param req current pending request + * @param date Timestamp + * @param assertion PVP2 S-Profil Assertion + * @param enableEncryption encrypt Assertion flag + * @return PVP2 S-Profile authentication response + * @throws InvalidAssertionEncryptionException In case of an error + */ + public static Response buildResponse(final MetadataProvider metadataProvider, + final String issuerEntityID, final RequestAbstractType req, final DateTime date, + final Assertion assertion, final boolean enableEncryption) + throws InvalidAssertionEncryptionException { + final Response authResponse = Saml2Utils.createSamlObject(Response.class); + + final Issuer nissuer = Saml2Utils.createSamlObject(Issuer.class); + + nissuer.setValue(issuerEntityID); + nissuer.setFormat(NameIDType.ENTITY); + authResponse.setIssuer(nissuer); + authResponse.setInResponseTo(req.getID()); + + // set responseID + final String remoteSessionID = Saml2Utils.getSecureIdentifier(); + authResponse.setID(remoteSessionID); + + + // SAML2 response required IssueInstant + authResponse.setIssueInstant(date); + + authResponse.setStatus(Saml2Utils.getSuccessStatus()); + + // check, if metadata includes an encryption key + final MetadataCredentialResolver mdCredResolver = + new MetadataCredentialResolver(metadataProvider); + + final CriteriaSet criteriaSet = new CriteriaSet(); + criteriaSet.add(new EntityIDCriteria(req.getIssuer().getValue())); + criteriaSet + .add(new MetadataCriteria(SPSSODescriptor.DEFAULT_ELEMENT_NAME, SAMLConstants.SAML20P_NS)); + criteriaSet.add(new UsageCriteria(UsageType.ENCRYPTION)); + + X509Credential encryptionCredentials = null; + try { + encryptionCredentials = (X509Credential) mdCredResolver.resolveSingle(criteriaSet); + + } catch (final SecurityException e2) { + log.warn("Can not extract the Assertion Encryption-Key from metadata", e2); + throw new InvalidAssertionEncryptionException(); + + } + + if (encryptionCredentials != null && enableEncryption) { + // encrypt SAML2 assertion + + try { + + final EncryptionParameters dataEncParams = new EncryptionParameters(); + dataEncParams.setAlgorithm(PvpConstants.DEFAULT_SYM_ENCRYPTION_METHODE); + + final List<KeyEncryptionParameters> keyEncParamList = new ArrayList<>(); + final KeyEncryptionParameters keyEncParam = new KeyEncryptionParameters(); + + keyEncParam.setEncryptionCredential(encryptionCredentials); + keyEncParam.setAlgorithm(PvpConstants.DEFAULT_ASYM_ENCRYPTION_METHODE); + final KeyInfoGeneratorFactory kigf = + org.opensaml.xml.Configuration.getGlobalSecurityConfiguration() + .getKeyInfoGeneratorManager().getDefaultManager().getFactory(encryptionCredentials); + keyEncParam.setKeyInfoGenerator(kigf.newInstance()); + keyEncParamList.add(keyEncParam); + + final Encrypter samlEncrypter = new Encrypter(dataEncParams, keyEncParamList); + // samlEncrypter.setKeyPlacement(KeyPlacement.INLINE); + samlEncrypter.setKeyPlacement(KeyPlacement.PEER); + + EncryptedAssertion encryptAssertion = null; + + encryptAssertion = samlEncrypter.encrypt(assertion); + + authResponse.getEncryptedAssertions().add(encryptAssertion); + + } catch (final EncryptionException e1) { + log.warn("Can not encrypt the PVP2 assertion", e1); + throw new InvalidAssertionEncryptionException(); + + } + + } else { + authResponse.getAssertions().add(assertion); + + } + + return authResponse; + } } diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/PVP2AssertionBuilder.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/PVP2AssertionBuilder.java deleted file mode 100644 index 2ccc2c9e..00000000 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/PVP2AssertionBuilder.java +++ /dev/null @@ -1,459 +0,0 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. - * - * Licensed under the EUPL, Version 1.2 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: - * https://joinup.ec.europa.eu/news/understanding-eupl-v12 - * - * 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.egiz.eaaf.modules.pvp2.idp.impl.builder; - -import java.security.MessageDigest; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import org.apache.commons.lang3.StringUtils; -import org.joda.time.DateTime; -import org.opensaml.common.xml.SAMLConstants; -import org.opensaml.saml2.core.Assertion; -import org.opensaml.saml2.core.Attribute; -import org.opensaml.saml2.core.AttributeQuery; -import org.opensaml.saml2.core.AttributeStatement; -import org.opensaml.saml2.core.Audience; -import org.opensaml.saml2.core.AudienceRestriction; -import org.opensaml.saml2.core.AuthnContext; -import org.opensaml.saml2.core.AuthnContextClassRef; -import org.opensaml.saml2.core.AuthnRequest; -import org.opensaml.saml2.core.AuthnStatement; -import org.opensaml.saml2.core.Conditions; -import org.opensaml.saml2.core.Issuer; -import org.opensaml.saml2.core.NameID; -import org.opensaml.saml2.core.RequestedAuthnContext; -import org.opensaml.saml2.core.Subject; -import org.opensaml.saml2.core.SubjectConfirmation; -import org.opensaml.saml2.core.SubjectConfirmationData; -import org.opensaml.saml2.core.impl.AuthnRequestImpl; -import org.opensaml.saml2.metadata.AssertionConsumerService; -import org.opensaml.saml2.metadata.AttributeConsumingService; -import org.opensaml.saml2.metadata.EntityDescriptor; -import org.opensaml.saml2.metadata.NameIDFormat; -import org.opensaml.saml2.metadata.RequestedAttribute; -import org.opensaml.saml2.metadata.SPSSODescriptor; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.util.Base64Utils; - -import at.gv.egiz.eaaf.core.api.data.EAAFConstants; -import at.gv.egiz.eaaf.core.api.data.ILoALevelMapper; -import at.gv.egiz.eaaf.core.api.idp.IAuthData; -import at.gv.egiz.eaaf.core.api.idp.ISPConfiguration; -import at.gv.egiz.eaaf.core.api.idp.slo.SLOInformationInterface; -import at.gv.egiz.eaaf.core.exceptions.UnavailableAttributeException; -import at.gv.egiz.eaaf.core.impl.data.Pair; -import at.gv.egiz.eaaf.core.impl.idp.controller.protocols.RequestImpl; -import at.gv.egiz.eaaf.core.impl.utils.Random; -import at.gv.egiz.eaaf.modules.pvp2.PVPConstants; -import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2Exception; -import at.gv.egiz.eaaf.modules.pvp2.exception.QAANotSupportedException; -import at.gv.egiz.eaaf.modules.pvp2.idp.api.builder.ISubjectNameIdGenerator; -import at.gv.egiz.eaaf.modules.pvp2.idp.exception.ResponderErrorException; -import at.gv.egiz.eaaf.modules.pvp2.idp.exception.UnprovideableAttributeException; -import at.gv.egiz.eaaf.modules.pvp2.idp.impl.PVPSProfilePendingRequest; -import at.gv.egiz.eaaf.modules.pvp2.impl.builder.PVPAttributeBuilder; -import at.gv.egiz.eaaf.modules.pvp2.impl.utils.QAALevelVerifier; -import at.gv.egiz.eaaf.modules.pvp2.impl.utils.SAML2Utils; - -@Service("PVP2AssertionBuilder") -public class PVP2AssertionBuilder implements PVPConstants { - - private static final Logger log = LoggerFactory.getLogger(PVP2AssertionBuilder.class); - @Autowired private ILoALevelMapper loaLevelMapper; - @Autowired private ISubjectNameIdGenerator subjectNameIdGenerator; - - - /** - * Build a PVP assertion as response for a SAML2 AttributeQuery request - * - * @param issuerEntityID EnitiyID, which should be used for this IDP response - * @param attrQuery AttributeQuery request from Service-Provider - * @param attrList List of PVP response attributes - * @param now Current time - * @param validTo ValidTo time of the assertion - * @param qaaLevel QAA level of the authentication - * @param sessionIndex SAML2 SessionIndex, which should be included * - * @return PVP 2.1 Assertion - * @throws PVP2Exception - */ - public Assertion buildAssertion(String issuerEntityID, AttributeQuery attrQuery, - List<Attribute> attrList, DateTime now, DateTime validTo, String qaaLevel, String sessionIndex) throws PVP2Exception { - - AuthnContextClassRef authnContextClassRef = SAML2Utils.createSAMLObject(AuthnContextClassRef.class); - authnContextClassRef.setAuthnContextClassRef(qaaLevel); - - NameID subjectNameID = SAML2Utils.createSAMLObject(NameID.class); - subjectNameID.setFormat(attrQuery.getSubject().getNameID().getFormat()); - subjectNameID.setValue(attrQuery.getSubject().getNameID().getValue()); - - SubjectConfirmationData subjectConfirmationData = null; - - return buildGenericAssertion(issuerEntityID, attrQuery.getIssuer().getValue(), now, - authnContextClassRef, attrList, subjectNameID, subjectConfirmationData, sessionIndex, - validTo); - } - - - /** - * Build a PVP 2.1 assertion as response of a SAML2 AuthnRequest - * - * @param issuerEntityID EnitiyID, which should be used for this IDP response - * @param pendingReq Current processed pendingRequest DAO - * @param authnRequest Current processed PVP AuthnRequest - * @param authData AuthenticationData of the user, which is already authenticated - * @param peerEntity SAML2 EntityDescriptor of the service-provider, which receives the response - * @param date TimeStamp - * @param assertionConsumerService SAML2 endpoint of the service-provider, which should be used - * @param sloInformation Single LogOut information DAO - * @return - * @throws PVP2Exception - */ - public Assertion buildAssertion(String issuerEntityID, PVPSProfilePendingRequest pendingReq, AuthnRequest authnRequest, - IAuthData authData, EntityDescriptor peerEntity, DateTime date, - AssertionConsumerService assertionConsumerService, SLOInformationInterface sloInformation) - throws PVP2Exception { - - ISPConfiguration oaParam = pendingReq.getServiceProviderConfiguration(); - AuthnContextClassRef authnContextClassRef = SAML2Utils.createSAMLObject(AuthnContextClassRef.class); - - //check if authn. request contains LoA - RequestedAuthnContext reqAuthnContext = authnRequest.getRequestedAuthnContext(); - if (reqAuthnContext == null) { - authnContextClassRef.setAuthnContextClassRef(authData.getEIDASQAALevel()); - - } else { - //authn. request requests LoA levels. To LoA validation - List<AuthnContextClassRef> reqAuthnContextClassRefIt = reqAuthnContext.getAuthnContextClassRefs(); - - //get matching mode from authn. request - String loaMatchingMode = EAAFConstants.EIDAS_LOA_MATCHING_MINIMUM; - if (reqAuthnContext.getComparison() != null && - StringUtils.isNotEmpty(reqAuthnContext.getComparison().toString())) - loaMatchingMode = reqAuthnContext.getComparison().toString(); - - //get requested LoAs - if (reqAuthnContextClassRefIt.size() == 0) { - QAALevelVerifier.verifyQAALevel(authData.getEIDASQAALevel(), - oaParam.getRequiredLoA(), loaMatchingMode); - authnContextClassRef.setAuthnContextClassRef(authData.getEIDASQAALevel()); - - } else { - List<String> eIDASLoaFromRequest = new ArrayList<String>(); - for (AuthnContextClassRef authnClassRef : reqAuthnContextClassRefIt) { - String qaa_uri = authnClassRef.getAuthnContextClassRef(); - - if (!qaa_uri.trim().startsWith(EAAFConstants.EIDAS_LOA_PREFIX)) { - if (loaLevelMapper != null) { - log.debug("Find no eIDAS LoA in AuthnReq. Start mapping process ... " ); - eIDASLoaFromRequest.add(loaLevelMapper.mapToeIDASLoA(qaa_uri.trim())); - - } else - log.debug("AuthnRequest contains no eIDAS LoA. NO LoA mapper FOUND, ignore " - + "'" + qaa_uri.trim() + "'"); - } else - eIDASLoaFromRequest.add(qaa_uri.trim()); - - } - - //stop process if no supported LoA scheme is requested - if (eIDASLoaFromRequest.isEmpty()) { - log.info("Authn. request contains no supported LoA level. Stop authentication process ... "); - throw new QAANotSupportedException("No supported LoA in Authn. request"); - - } - - //verifiy LoAs from request to authentication LoA - QAALevelVerifier.verifyQAALevel(authData.getEIDASQAALevel(), eIDASLoaFromRequest , loaMatchingMode); - authnContextClassRef.setAuthnContextClassRef(authData.getEIDASQAALevel()); - - } - } - - - //load SPSS decriptor from service-provider metadata - SPSSODescriptor spSSODescriptor = peerEntity.getSPSSODescriptor(SAMLConstants.SAML20P_NS); - - //add Attributes to Assertion - List<Attribute> attrList = new ArrayList<Attribute>(); - if (spSSODescriptor.getAttributeConsumingServices() != null && - spSSODescriptor.getAttributeConsumingServices().size() > 0) { - - Integer aIdx = authnRequest.getAttributeConsumingServiceIndex(); - int idx = 0; - - AttributeConsumingService attributeConsumingService = null; - if (aIdx != null) { - idx = aIdx.intValue(); - attributeConsumingService = spSSODescriptor - .getAttributeConsumingServices().get(idx); - - } else { - List<AttributeConsumingService> attrConsumingServiceList = spSSODescriptor.getAttributeConsumingServices(); - for (AttributeConsumingService el : attrConsumingServiceList) { - if (el.isDefault()) - attributeConsumingService = el; - } - } - - /* - * TODO: maybe use first AttributeConsumingService if no is selected - * in request or on service is marked as default - * - */ - if (attributeConsumingService == null ) { - List<AttributeConsumingService> attrConsumingServiceList = spSSODescriptor.getAttributeConsumingServices(); - if (attrConsumingServiceList != null && !attrConsumingServiceList.isEmpty()) - attributeConsumingService = attrConsumingServiceList.get(0); - - } - - - if (attributeConsumingService != null) { - Iterator<RequestedAttribute> it = attributeConsumingService - .getRequestAttributes().iterator(); - while (it.hasNext()) { - RequestedAttribute reqAttribut = it.next(); - try { - Attribute attr = PVPAttributeBuilder.buildAttribute( - reqAttribut.getName(), oaParam, authData); - if (attr == null) { - if (reqAttribut.isRequired()) { - throw new UnprovideableAttributeException( - reqAttribut.getName()); - } - } else { - attrList.add(attr); - } - - } catch (UnavailableAttributeException e) { - log.info( - "Attribute generation for " - + reqAttribut.getFriendlyName() + " not possible."); - if (reqAttribut.isRequired()) { - throw new UnprovideableAttributeException( - reqAttribut.getName()); - } - - - } catch (PVP2Exception e) { - log.info( - "Attribute generation failed! for " - + reqAttribut.getFriendlyName()); - if (reqAttribut.isRequired()) { - throw new UnprovideableAttributeException( - reqAttribut.getName()); - } - - } catch (Exception e) { - log.warn( - "General Attribute generation failed! for " - + reqAttribut.getFriendlyName(), e); - if (reqAttribut.isRequired()) { - throw new UnprovideableAttributeException( - reqAttribut.getName()); - } - - } - } - } - } - - //generate subjectNameId - NameID subjectNameID = SAML2Utils.createSAMLObject(NameID.class); - Pair<String, String> subjectNameIdPair = subjectNameIdGenerator.generateSubjectNameId(authData, oaParam); - subjectNameID.setValue(subjectNameIdPair.getFirst()); - subjectNameID.setNameQualifier(subjectNameIdPair.getSecond()); - - //get NameIDFormat from request - String nameIDFormat = NameID.TRANSIENT; - AuthnRequest authnReq = (AuthnRequestImpl) authnRequest; - if (authnReq.getNameIDPolicy() != null && - StringUtils.isNotEmpty(authnReq.getNameIDPolicy().getFormat())) { - nameIDFormat = authnReq.getNameIDPolicy().getFormat(); - - } else { - //get NameIDFormat from metadata - List<NameIDFormat> metadataNameIDFormats = spSSODescriptor.getNameIDFormats(); - - if (metadataNameIDFormats != null) { - - for (NameIDFormat el : metadataNameIDFormats) { - if (NameID.PERSISTENT.equals(el.getFormat())) { - nameIDFormat = NameID.PERSISTENT; - break; - - } else if (NameID.TRANSIENT.equals(el.getFormat()) || - NameID.UNSPECIFIED.equals(el.getFormat())) - break; - - } - } - } - - if (NameID.TRANSIENT.equals(nameIDFormat) || NameID.UNSPECIFIED.equals(nameIDFormat)) { - String random = Random.nextHexRandom32(); - String nameID = subjectNameID.getValue(); - - try { - MessageDigest md = MessageDigest.getInstance("SHA-1"); - byte[] hash = md.digest((nameID + random).getBytes("ISO-8859-1")); - subjectNameID.setValue(Base64Utils.encodeToString(hash)); - subjectNameID.setNameQualifier(null); - subjectNameID.setFormat(NameID.TRANSIENT); - - } catch (Exception e) { - log.warn("PVP2 subjectNameID error", e); - throw new ResponderErrorException("internal.03", null, e); - - } - - } else - subjectNameID.setFormat(nameIDFormat); - - - String sessionIndex = null; - - //if request is a reauthentication and NameIDFormat match reuse old session information - if (StringUtils.isNotEmpty(authData.getNameID()) && - StringUtils.isNotEmpty(authData.getNameIDFormat()) && - nameIDFormat.equals(authData.getNameIDFormat())) { - subjectNameID.setValue(authData.getNameID()); - sessionIndex = authData.getSessionIndex(); - - } - - // - if (StringUtils.isEmpty(sessionIndex)) - sessionIndex = SAML2Utils.getSecureIdentifier(); - - SubjectConfirmationData subjectConfirmationData = SAML2Utils - .createSAMLObject(SubjectConfirmationData.class); - subjectConfirmationData.setInResponseTo(authnRequest.getID()); - subjectConfirmationData.setNotOnOrAfter(new DateTime(authData.getSsoSessionValidTo().getTime())); - - //set 'recipient' attribute in subjectConformationData - subjectConfirmationData.setRecipient(assertionConsumerService.getLocation()); - - //set IP address of the user machine as 'Address' attribute in subjectConformationData - String usersIPAddress = pendingReq.getRawData( - RequestImpl.DATAID_REQUESTER_IP_ADDRESS, String.class); - if (StringUtils.isNotEmpty(usersIPAddress)) - subjectConfirmationData.setAddress(usersIPAddress); - - //set SLO information - sloInformation.setUserNameIdentifier(subjectNameID.getValue()); - sloInformation.setNameIDFormat(subjectNameID.getFormat()); - sloInformation.setSessionIndex(sessionIndex); - - return buildGenericAssertion(issuerEntityID, peerEntity.getEntityID(), date, authnContextClassRef, attrList, subjectNameID, subjectConfirmationData, sessionIndex, subjectConfirmationData.getNotOnOrAfter()); - } - - /** - * - * @param issuer IDP EntityID - * @param entityID Service Provider EntityID - * @param date - * @param authnContextClassRef - * @param attrList - * @param subjectNameID - * @param subjectConfirmationData - * @param sessionIndex - * @param isValidTo - * @return - * @throws ConfigurationException - */ - - public Assertion buildGenericAssertion(String issuer, String entityID, DateTime date, - AuthnContextClassRef authnContextClassRef, List<Attribute> attrList, - NameID subjectNameID, SubjectConfirmationData subjectConfirmationData, - String sessionIndex, DateTime isValidTo) throws ResponderErrorException { - Assertion assertion = SAML2Utils.createSAMLObject(Assertion.class); - - AuthnContext authnContext = SAML2Utils - .createSAMLObject(AuthnContext.class); - authnContext.setAuthnContextClassRef(authnContextClassRef); - - AuthnStatement authnStatement = SAML2Utils - .createSAMLObject(AuthnStatement.class); - - authnStatement.setAuthnInstant(date); - authnStatement.setSessionIndex(sessionIndex); - authnStatement.setAuthnContext(authnContext); - - assertion.getAuthnStatements().add(authnStatement); - - AttributeStatement attributeStatement = SAML2Utils - .createSAMLObject(AttributeStatement.class); - attributeStatement.getAttributes().addAll(attrList); - if (attributeStatement.getAttributes().size() > 0) { - assertion.getAttributeStatements().add(attributeStatement); - } - - Subject subject = SAML2Utils.createSAMLObject(Subject.class); - subject.setNameID(subjectNameID); - - SubjectConfirmation subjectConfirmation = SAML2Utils - .createSAMLObject(SubjectConfirmation.class); - subjectConfirmation.setMethod(SubjectConfirmation.METHOD_BEARER); - subjectConfirmation.setSubjectConfirmationData(subjectConfirmationData); - - subject.getSubjectConfirmations().add(subjectConfirmation); - - Conditions conditions = SAML2Utils.createSAMLObject(Conditions.class); - AudienceRestriction audienceRestriction = SAML2Utils - .createSAMLObject(AudienceRestriction.class); - Audience audience = SAML2Utils.createSAMLObject(Audience.class); - - audience.setAudienceURI(entityID); - audienceRestriction.getAudiences().add(audience); - conditions.setNotBefore(date); - conditions.setNotOnOrAfter(isValidTo); - - conditions.getAudienceRestrictions().add(audienceRestriction); - - assertion.setConditions(conditions); - - Issuer issuerObj = SAML2Utils.createSAMLObject(Issuer.class); - - if (issuer.endsWith("/")) - issuer = issuer.substring(0, issuer.length()-1); - issuerObj.setValue(issuer); - issuerObj.setFormat(NameID.ENTITY); - - assertion.setIssuer(issuerObj); - assertion.setSubject(subject); - assertion.setID(SAML2Utils.getSecureIdentifier()); - assertion.setIssueInstant(date); - - return assertion; - } -} diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/Pvp2AssertionBuilder.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/Pvp2AssertionBuilder.java new file mode 100644 index 00000000..79de4567 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/Pvp2AssertionBuilder.java @@ -0,0 +1,465 @@ +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 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: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * 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.egiz.eaaf.modules.pvp2.idp.impl.builder; + +import java.security.MessageDigest; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import at.gv.egiz.eaaf.core.api.data.EAAFConstants; +import at.gv.egiz.eaaf.core.api.data.ILoALevelMapper; +import at.gv.egiz.eaaf.core.api.idp.IAuthData; +import at.gv.egiz.eaaf.core.api.idp.IspConfiguration; +import at.gv.egiz.eaaf.core.api.idp.slo.SloInformationInterface; +import at.gv.egiz.eaaf.core.exceptions.UnavailableAttributeException; +import at.gv.egiz.eaaf.core.impl.data.Pair; +import at.gv.egiz.eaaf.core.impl.idp.controller.protocols.RequestImpl; +import at.gv.egiz.eaaf.core.impl.utils.Random; +import at.gv.egiz.eaaf.modules.pvp2.PvpConstants; +import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2Exception; +import at.gv.egiz.eaaf.modules.pvp2.exception.QaaNotSupportedException; +import at.gv.egiz.eaaf.modules.pvp2.idp.api.builder.ISubjectNameIdGenerator; +import at.gv.egiz.eaaf.modules.pvp2.idp.exception.ResponderErrorException; +import at.gv.egiz.eaaf.modules.pvp2.idp.exception.UnprovideableAttributeException; +import at.gv.egiz.eaaf.modules.pvp2.idp.impl.PvpSProfilePendingRequest; +import at.gv.egiz.eaaf.modules.pvp2.impl.builder.PvpAttributeBuilder; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.QaaLevelVerifier; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; +import org.apache.commons.lang3.StringUtils; +import org.joda.time.DateTime; +import org.opensaml.common.xml.SAMLConstants; +import org.opensaml.saml2.core.Assertion; +import org.opensaml.saml2.core.Attribute; +import org.opensaml.saml2.core.AttributeQuery; +import org.opensaml.saml2.core.AttributeStatement; +import org.opensaml.saml2.core.Audience; +import org.opensaml.saml2.core.AudienceRestriction; +import org.opensaml.saml2.core.AuthnContext; +import org.opensaml.saml2.core.AuthnContextClassRef; +import org.opensaml.saml2.core.AuthnRequest; +import org.opensaml.saml2.core.AuthnStatement; +import org.opensaml.saml2.core.Conditions; +import org.opensaml.saml2.core.Issuer; +import org.opensaml.saml2.core.NameID; +import org.opensaml.saml2.core.NameIDType; +import org.opensaml.saml2.core.RequestedAuthnContext; +import org.opensaml.saml2.core.Subject; +import org.opensaml.saml2.core.SubjectConfirmation; +import org.opensaml.saml2.core.SubjectConfirmationData; +import org.opensaml.saml2.metadata.AssertionConsumerService; +import org.opensaml.saml2.metadata.AttributeConsumingService; +import org.opensaml.saml2.metadata.EntityDescriptor; +import org.opensaml.saml2.metadata.NameIDFormat; +import org.opensaml.saml2.metadata.RequestedAttribute; +import org.opensaml.saml2.metadata.SPSSODescriptor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.Base64Utils; + +@Service("PVP2AssertionBuilder") +public class Pvp2AssertionBuilder implements PvpConstants { + + private static final Logger log = LoggerFactory.getLogger(Pvp2AssertionBuilder.class); + @Autowired + private ILoALevelMapper loaLevelMapper; + @Autowired + private ISubjectNameIdGenerator subjectNameIdGenerator; + + + /** + * Build a PVP assertion as response for a SAML2 AttributeQuery request. + * + * @param issuerEntityID EnitiyID, which should be used for this IDP response + * @param attrQuery AttributeQuery request from Service-Provider + * @param attrList List of PVP response attributes + * @param now Current time + * @param validTo ValidTo time of the assertion + * @param qaaLevel QAA level of the authentication + * @param sessionIndex SAML2 SessionIndex, which should be included * + * @return PVP 2.1 Assertion + * @throws Pvp2Exception In case of an error + */ + public Assertion buildAssertion(final String issuerEntityID, final AttributeQuery attrQuery, + final List<Attribute> attrList, final DateTime now, final DateTime validTo, + final String qaaLevel, final String sessionIndex) throws Pvp2Exception { + + final AuthnContextClassRef authnContextClassRef = + Saml2Utils.createSamlObject(AuthnContextClassRef.class); + authnContextClassRef.setAuthnContextClassRef(qaaLevel); + + final NameID subjectNameID = Saml2Utils.createSamlObject(NameID.class); + subjectNameID.setFormat(attrQuery.getSubject().getNameID().getFormat()); + subjectNameID.setValue(attrQuery.getSubject().getNameID().getValue()); + + final SubjectConfirmationData subjectConfirmationData = null; + + return buildGenericAssertion(issuerEntityID, attrQuery.getIssuer().getValue(), now, + authnContextClassRef, attrList, subjectNameID, subjectConfirmationData, sessionIndex, + validTo); + } + + + /** + * Build a PVP 2.1 assertion as response of a SAML2 AuthnRequest. + * + * @param issuerEntityID EnitiyID, which should be used for this IDP response + * @param pendingReq Current processed pendingRequest DAO + * @param authnRequest Current processed PVP AuthnRequest + * @param authData AuthenticationData of the user, which is already authenticated + * @param peerEntity SAML2 EntityDescriptor of the service-provider, which receives the response + * @param date TimeStamp + * @param assertionConsumerService SAML2 endpoint of the service-provider, which should be used + * @param sloInformation Single LogOut information DAO + * @return PVP2 S-Profil Assertion + * @throws Pvp2Exception In case of an error + */ + public Assertion buildAssertion(final String issuerEntityID, + final PvpSProfilePendingRequest pendingReq, final AuthnRequest authnRequest, + final IAuthData authData, final EntityDescriptor peerEntity, final DateTime date, + final AssertionConsumerService assertionConsumerService, + final SloInformationInterface sloInformation) throws Pvp2Exception { + + final IspConfiguration oaParam = pendingReq.getServiceProviderConfiguration(); + final AuthnContextClassRef authnContextClassRef = + Saml2Utils.createSamlObject(AuthnContextClassRef.class); + + // check if authn. request contains LoA + final RequestedAuthnContext reqAuthnContext = authnRequest.getRequestedAuthnContext(); + if (reqAuthnContext == null) { + authnContextClassRef.setAuthnContextClassRef(authData.getEidasQaaLevel()); + + } else { + // authn. request requests LoA levels. To LoA validation + final List<AuthnContextClassRef> reqAuthnContextClassRefIt = + reqAuthnContext.getAuthnContextClassRefs(); + + // get matching mode from authn. request + String loaMatchingMode = EAAFConstants.EIDAS_LOA_MATCHING_MINIMUM; + if (reqAuthnContext.getComparison() != null + && StringUtils.isNotEmpty(reqAuthnContext.getComparison().toString())) { + loaMatchingMode = reqAuthnContext.getComparison().toString(); + } + + // get requested LoAs + if (reqAuthnContextClassRefIt.size() == 0) { + QaaLevelVerifier.verifyQaaLevel(authData.getEidasQaaLevel(), oaParam.getRequiredLoA(), + loaMatchingMode); + authnContextClassRef.setAuthnContextClassRef(authData.getEidasQaaLevel()); + + } else { + final List<String> eidasLoaFromRequest = new ArrayList<>(); + for (final AuthnContextClassRef authnClassRef : reqAuthnContextClassRefIt) { + final String qaa_uri = authnClassRef.getAuthnContextClassRef(); + + if (!qaa_uri.trim().startsWith(EAAFConstants.EIDAS_LOA_PREFIX)) { + if (loaLevelMapper != null) { + log.debug("Find no eIDAS LoA in AuthnReq. Start mapping process ... "); + eidasLoaFromRequest.add(loaLevelMapper.mapToeIDASLoA(qaa_uri.trim())); + + } else { + log.debug("AuthnRequest contains no eIDAS LoA. NO LoA mapper FOUND, ignore " + "'" + + qaa_uri.trim() + "'"); + } + } else { + eidasLoaFromRequest.add(qaa_uri.trim()); + } + + } + + // stop process if no supported LoA scheme is requested + if (eidasLoaFromRequest.isEmpty()) { + log.info( + "Authn. request contains no supported LoA level. Stop authentication process ... "); + throw new QaaNotSupportedException("No supported LoA in Authn. request"); + + } + + // verifiy LoAs from request to authentication LoA + QaaLevelVerifier.verifyQaaLevel(authData.getEidasQaaLevel(), eidasLoaFromRequest, + loaMatchingMode); + authnContextClassRef.setAuthnContextClassRef(authData.getEidasQaaLevel()); + + } + } + + + // load SPSS decriptor from service-provider metadata + final SPSSODescriptor spSsoDescriptor = peerEntity.getSPSSODescriptor(SAMLConstants.SAML20P_NS); + + // add Attributes to Assertion + final List<Attribute> attrList = new ArrayList<>(); + if (spSsoDescriptor.getAttributeConsumingServices() != null + && spSsoDescriptor.getAttributeConsumingServices().size() > 0) { + + final Integer aIdx = authnRequest.getAttributeConsumingServiceIndex(); + int idx = 0; + + AttributeConsumingService attributeConsumingService = null; + if (aIdx != null) { + idx = aIdx.intValue(); + attributeConsumingService = spSsoDescriptor.getAttributeConsumingServices().get(idx); + + } else { + final List<AttributeConsumingService> attrConsumingServiceList = + spSsoDescriptor.getAttributeConsumingServices(); + for (final AttributeConsumingService el : attrConsumingServiceList) { + if (el.isDefault()) { + attributeConsumingService = el; + } + } + } + + /* + * TODO: maybe use first AttributeConsumingService if no is selected in request or on service + * is marked as default + * + */ + if (attributeConsumingService == null) { + final List<AttributeConsumingService> attrConsumingServiceList = + spSsoDescriptor.getAttributeConsumingServices(); + if (attrConsumingServiceList != null && !attrConsumingServiceList.isEmpty()) { + attributeConsumingService = attrConsumingServiceList.get(0); + } + + } + + + if (attributeConsumingService != null) { + final Iterator<RequestedAttribute> it = + attributeConsumingService.getRequestAttributes().iterator(); + while (it.hasNext()) { + final RequestedAttribute reqAttribut = it.next(); + try { + final Attribute attr = + PvpAttributeBuilder.buildAttribute(reqAttribut.getName(), oaParam, authData); + if (attr == null) { + if (reqAttribut.isRequired()) { + throw new UnprovideableAttributeException(reqAttribut.getName()); + } + } else { + attrList.add(attr); + } + + } catch (final UnavailableAttributeException e) { + log.info( + "Attribute generation for " + reqAttribut.getFriendlyName() + " not possible."); + if (reqAttribut.isRequired()) { + throw new UnprovideableAttributeException(reqAttribut.getName()); + } + + + } catch (final Pvp2Exception e) { + log.info("Attribute generation failed! for " + reqAttribut.getFriendlyName()); + if (reqAttribut.isRequired()) { + throw new UnprovideableAttributeException(reqAttribut.getName()); + } + + } catch (final Exception e) { + log.warn("General Attribute generation failed! for " + reqAttribut.getFriendlyName(), + e); + if (reqAttribut.isRequired()) { + throw new UnprovideableAttributeException(reqAttribut.getName()); + } + + } + } + } + } + + // generate subjectNameId + final NameID subjectNameID = Saml2Utils.createSamlObject(NameID.class); + final Pair<String, String> subjectNameIdPair = + subjectNameIdGenerator.generateSubjectNameId(authData, oaParam); + subjectNameID.setValue(subjectNameIdPair.getFirst()); + subjectNameID.setNameQualifier(subjectNameIdPair.getSecond()); + + // get NameIDFormat from request + String nameIdFormat = NameIDType.TRANSIENT; + final AuthnRequest authnReq = authnRequest; + if (authnReq.getNameIDPolicy() != null + && StringUtils.isNotEmpty(authnReq.getNameIDPolicy().getFormat())) { + nameIdFormat = authnReq.getNameIDPolicy().getFormat(); + + } else { + // get NameIDFormat from metadata + final List<NameIDFormat> metadataNameIdFormats = spSsoDescriptor.getNameIDFormats(); + + if (metadataNameIdFormats != null) { + + for (final NameIDFormat el : metadataNameIdFormats) { + if (NameIDType.PERSISTENT.equals(el.getFormat())) { + nameIdFormat = NameIDType.PERSISTENT; + break; + + } else if (NameIDType.TRANSIENT.equals(el.getFormat()) + || NameIDType.UNSPECIFIED.equals(el.getFormat())) { + break; + } + + } + } + } + + if (NameIDType.TRANSIENT.equals(nameIdFormat) || NameIDType.UNSPECIFIED.equals(nameIdFormat)) { + final String random = Random.nextHexRandom32(); + final String nameID = subjectNameID.getValue(); + + try { + final MessageDigest md = MessageDigest.getInstance("SHA-1"); + final byte[] hash = md.digest((nameID + random).getBytes("ISO-8859-1")); + subjectNameID.setValue(Base64Utils.encodeToString(hash)); + subjectNameID.setNameQualifier(null); + subjectNameID.setFormat(NameIDType.TRANSIENT); + + } catch (final Exception e) { + log.warn("PVP2 subjectNameID error", e); + throw new ResponderErrorException("internal.03", null, e); + + } + + } else { + subjectNameID.setFormat(nameIdFormat); + } + + + String sessionIndex = null; + + // if request is a reauthentication and NameIDFormat match reuse old session information + if (StringUtils.isNotEmpty(authData.getNameID()) + && StringUtils.isNotEmpty(authData.getNameIdFormat()) + && nameIdFormat.equals(authData.getNameIdFormat())) { + subjectNameID.setValue(authData.getNameID()); + sessionIndex = authData.getSessionIndex(); + + } + + // + if (StringUtils.isEmpty(sessionIndex)) { + sessionIndex = Saml2Utils.getSecureIdentifier(); + } + + final SubjectConfirmationData subjectConfirmationData = + Saml2Utils.createSamlObject(SubjectConfirmationData.class); + subjectConfirmationData.setInResponseTo(authnRequest.getID()); + subjectConfirmationData + .setNotOnOrAfter(new DateTime(authData.getSsoSessionValidTo().getTime())); + + // set 'recipient' attribute in subjectConformationData + subjectConfirmationData.setRecipient(assertionConsumerService.getLocation()); + + // set IP address of the user machine as 'Address' attribute in subjectConformationData + final String usersIpAddress = + pendingReq.getRawData(RequestImpl.DATAID_REQUESTER_IP_ADDRESS, String.class); + if (StringUtils.isNotEmpty(usersIpAddress)) { + subjectConfirmationData.setAddress(usersIpAddress); + } + + // set SLO information + sloInformation.setUserNameIdentifier(subjectNameID.getValue()); + sloInformation.setNameIdFormat(subjectNameID.getFormat()); + sloInformation.setSessionIndex(sessionIndex); + + return buildGenericAssertion(issuerEntityID, peerEntity.getEntityID(), date, + authnContextClassRef, attrList, subjectNameID, subjectConfirmationData, sessionIndex, + subjectConfirmationData.getNotOnOrAfter()); + } + + /** + * Build generic part of PVP S-Profile Assertion. + * + * @param issuer IDP EntityID + * @param entityID Service Provider EntityID + * @param date Timestamp + * @param authnContextClassRef SAML2 AuthnContextClassReference + * @param attrList List of attributes + * @param subjectNameID SubjectNameId + * @param subjectConfirmationData SubjectConfirmationInformation + * @param sessionIndex SessionIndex + * @param isValidTo ValidTo Timestamp + * @return PVP S-Profile Assertion + * @throws ConfigurationException In case on an error + */ + + public Assertion buildGenericAssertion(String issuer, final String entityID, final DateTime date, + final AuthnContextClassRef authnContextClassRef, final List<Attribute> attrList, + final NameID subjectNameID, final SubjectConfirmationData subjectConfirmationData, + final String sessionIndex, final DateTime isValidTo) throws ResponderErrorException { + final Assertion assertion = Saml2Utils.createSamlObject(Assertion.class); + + final AuthnContext authnContext = Saml2Utils.createSamlObject(AuthnContext.class); + authnContext.setAuthnContextClassRef(authnContextClassRef); + + final AuthnStatement authnStatement = Saml2Utils.createSamlObject(AuthnStatement.class); + + authnStatement.setAuthnInstant(date); + authnStatement.setSessionIndex(sessionIndex); + authnStatement.setAuthnContext(authnContext); + + assertion.getAuthnStatements().add(authnStatement); + + final AttributeStatement attributeStatement = + Saml2Utils.createSamlObject(AttributeStatement.class); + attributeStatement.getAttributes().addAll(attrList); + if (attributeStatement.getAttributes().size() > 0) { + assertion.getAttributeStatements().add(attributeStatement); + } + + final Subject subject = Saml2Utils.createSamlObject(Subject.class); + subject.setNameID(subjectNameID); + + final SubjectConfirmation subjectConfirmation = + Saml2Utils.createSamlObject(SubjectConfirmation.class); + subjectConfirmation.setMethod(SubjectConfirmation.METHOD_BEARER); + subjectConfirmation.setSubjectConfirmationData(subjectConfirmationData); + + subject.getSubjectConfirmations().add(subjectConfirmation); + + final Conditions conditions = Saml2Utils.createSamlObject(Conditions.class); + final AudienceRestriction audienceRestriction = + Saml2Utils.createSamlObject(AudienceRestriction.class); + final Audience audience = Saml2Utils.createSamlObject(Audience.class); + + audience.setAudienceURI(entityID); + audienceRestriction.getAudiences().add(audience); + conditions.setNotBefore(date); + conditions.setNotOnOrAfter(isValidTo); + + conditions.getAudienceRestrictions().add(audienceRestriction); + + assertion.setConditions(conditions); + + final Issuer issuerObj = Saml2Utils.createSamlObject(Issuer.class); + + if (issuer.endsWith("/")) { + issuer = issuer.substring(0, issuer.length() - 1); + } + issuerObj.setValue(issuer); + issuerObj.setFormat(NameIDType.ENTITY); + + assertion.setIssuer(issuerObj); + assertion.setSubject(subject); + assertion.setID(Saml2Utils.getSecureIdentifier()); + assertion.setIssueInstant(date); + + return assertion; + } +} diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider b/eaaf_modules/eaaf_module_pvp2_idp/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider index cda12a62..c3c68e20 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider @@ -1 +1 @@ -at.gv.egiz.eaaf.modules.pvp2.idp.PVP2SProfileIDPSpringResourceProvider
\ No newline at end of file +at.gv.egiz.eaaf.modules.pvp2.idp.Pvp2SProfileIdpSpringResourceProvider
\ No newline at end of file diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/resources/eaaf_pvp_idp.beans.xml b/eaaf_modules/eaaf_module_pvp2_idp/src/main/resources/eaaf_pvp_idp.beans.xml index b01a09ff..d29b5aba 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/resources/eaaf_pvp_idp.beans.xml +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/resources/eaaf_pvp_idp.beans.xml @@ -1,22 +1,19 @@ <?xml version="1.0" encoding="UTF-8"?> -<!-- - --> - <beans xmlns="http://www.springframework.org/schema/beans" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xmlns:context="http://www.springframework.org/schema/context" - xmlns:tx="http://www.springframework.org/schema/tx" - xmlns:aop="http://www.springframework.org/schema/aop" - xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd - http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd - http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd - http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"> - - <bean id="PVP2AssertionBuilder" - class="at.gv.egiz.eaaf.modules.pvp2.idp.impl.builder.PVP2AssertionBuilder" /> - - <bean id="PVPSProfilePendingRequest" - class="at.gv.egiz.eaaf.modules.pvp2.idp.impl.PVPSProfilePendingRequest" - scope="prototype"/> - + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:context="http://www.springframework.org/schema/context" + xmlns:tx="http://www.springframework.org/schema/tx" + xmlns:aop="http://www.springframework.org/schema/aop" + xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd + http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd + http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd + http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"> + + <bean id="PVP2AssertionBuilder" + class="at.gv.egiz.eaaf.modules.pvp2.idp.impl.builder.Pvp2AssertionBuilder" /> + + <bean id="PVPSProfilePendingRequest" + class="at.gv.egiz.eaaf.modules.pvp2.idp.impl.PvpSProfilePendingRequest" + scope="prototype" /> + </beans>
\ No newline at end of file |