diff options
Diffstat (limited to 'id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks')
3 files changed, 423 insertions, 1 deletions
diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/CollectAddtionalAttributesTask.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/CollectAddtionalAttributesTask.java new file mode 100644 index 000000000..a58bc4f8d --- /dev/null +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/CollectAddtionalAttributesTask.java @@ -0,0 +1,181 @@ +package at.gv.egovernment.moa.id.auth.modules.eidas.tasks; + +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.google.common.collect.UnmodifiableIterator; + +import at.gv.egiz.eaaf.core.api.idp.IAuthData; +import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; +import at.gv.egiz.eaaf.core.api.storage.ITransactionStorage; +import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException; +import at.gv.egiz.eaaf.core.impl.idp.auth.modules.AbstractAuthServletTask; +import at.gv.egiz.eaaf.core.impl.idp.builder.attributes.BPKAttributeBuilder; +import at.gv.egiz.eaaf.core.impl.utils.Random; +import at.gv.egiz.eid4u.api.attributes.Definitions; +import at.gv.egovernment.moa.id.auth.builder.AuthenticationDataBuilder; +import at.gv.egovernment.moa.id.auth.data.AuthenticationSessionWrapper; +import at.gv.egovernment.moa.id.auth.modules.eidas.eID4UConstants; +import at.gv.egovernment.moa.id.auth.modules.eidas.eid4u.utils.AttributeScopeMapper; +import at.gv.egovernment.moa.id.protocols.builder.attributes.SimpleStringAttributeGenerator; +import at.gv.egovernment.moa.id.protocols.eidas.EIDASData; +import at.gv.egovernment.moa.id.protocols.oauth20.OAuth20Constants; +import at.gv.egovernment.moa.id.protocols.oauth20.OAuth20SessionObject; +import at.gv.egovernment.moa.id.protocols.oauth20.protocol.OAuth20AuthAction; +import at.gv.egovernment.moa.id.protocols.oauth20.protocol.OAuth20AuthRequest; +import at.gv.egovernment.moa.id.protocols.oauth20.protocol.OAuth20Protocol; +import at.gv.egovernment.moa.id.util.CookieUtils; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.MiscUtil; +import eu.eidas.auth.commons.attribute.ImmutableAttributeMap; +import eu.eidas.auth.commons.attribute.ImmutableAttributeMap.Builder; +import eu.eidas.auth.commons.attribute.ImmutableAttributeMap.ImmutableAttributeEntry; + +@Component("CollectAddtionalAttributesTask") +public class CollectAddtionalAttributesTask extends AbstractAuthServletTask { + + @Autowired private OAuth20AuthAction openIDAuthAction; + @Autowired private ITransactionStorage transactionStorage; + @Autowired private AuthenticationDataBuilder authDataBuilder; + + @Override + public void execute(ExecutionContext context, HttpServletRequest httpReq, HttpServletResponse httpResp) + throws TaskExecutionException { + try{ + context.put(eID4UConstants.PROCESS_CONTEXT_FLAG_EID4U_AP_ACCESS, false); + + if (pendingReq instanceof EIDASData) { + EIDASData eidasReq = (EIDASData) pendingReq; + Logger.debug("Find eIDAS Auth. Req. Check if eID4U attributes are requested ..."); + + //select all eID4U attributes from requested attributes + Builder reqEid4uAttrListBuilder = ImmutableAttributeMap.builder(); + ImmutableAttributeMap reqAttrList = eidasReq.getEidasRequestedAttributes(); + for (String el : Definitions.EID4UATTRIBUTEELIST) { + if(reqAttrList.getAttributeValuesByNameUri(el) != null) { + Logger.debug("Find eID4U attr: " + el); + reqEid4uAttrListBuilder.put(reqAttrList.getDefinitionByNameUri(el)); + + } + } + + //collect eID4U attributes, if some attributes are selected before + ImmutableAttributeMap reqEid4uAttrList = reqEid4uAttrListBuilder.build(); + if (reqEid4uAttrList != null && reqEid4uAttrList.size() > 0) { + Logger.info("Starting eID4U attribute collection process ... "); + + //mark execution context with eID4U AP flag + context.put(eID4UConstants.PROCESS_CONTEXT_FLAG_EID4U_AP_ACCESS, true); + + //load connection parameters to TUG + String uniqueID = authConfig.getBasicConfiguration(eID4UConstants.CONFIG_PROPS_AP_CONSENT_ENTITYID); + String redirectURI = authConfig.getBasicConfiguration(eID4UConstants.CONFIG_PROPS_AP_CONSENT_URL); + String scopes = authConfig.getBasicConfiguration(eID4UConstants.CONFIG_PROPS_AP_SCOPES); + + if (MiscUtil.isEmpty(scopes)) { + //generate scope from attributes + scopes = mapReqAttributesIntoScopes(reqEid4uAttrList); + + } + + Logger.debug("Load eID4U AP-Config:" + + " EntityID: " + uniqueID + + " RedirectURL:" + redirectURI + + " Scopes: " + scopes); + + + /* + *build openID and set connect token + */ + + //generate fake OpenID_Connect request + OAuth20AuthRequest fakeOpenIDReq = new OAuth20AuthRequest(); + fakeOpenIDReq.initialize(httpReq, authConfig); + fakeOpenIDReq.setSPEntityId(uniqueID); + fakeOpenIDReq.setModule(OAuth20Protocol.NAME); + fakeOpenIDReq.setOnlineApplicationConfiguration(authConfig.getServiceProviderConfiguration(uniqueID)); + fakeOpenIDReq.setScope("openId profile"); + + //populate with SessionData + fakeOpenIDReq.setRawDataToTransaction( + pendingReq.getSessionData(AuthenticationSessionWrapper.class) + .getKeyValueRepresentationFromAuthSession()); + + //generate authData + IAuthData authData = authDataBuilder.buildAuthenticationData(fakeOpenIDReq); + + //generate OpenIDConenct token + String accessToken = Random.nextHexRandom32(); + OAuth20SessionObject o = new OAuth20SessionObject(); + o.setScope(fakeOpenIDReq.getScope()); + o.setCode(accessToken); + Map<String, Object> idToken = openIDAuthAction.generateIDToken(o, fakeOpenIDReq, authData, accessToken); + o.setAuthDataSession(idToken); + transactionStorage.put(accessToken, o, -1); + + //forward to TUG + httpResp.setStatus(HttpServletResponse.SC_FOUND); + redirectURI = addURLParameter(redirectURI, OAuth20Constants.PARAM_OPENID_CODE, accessToken); + redirectURI = addURLParameter(redirectURI, OAuth20Constants.PARAM_SCOPE, scopes); + redirectURI = addURLParameter(redirectURI, OAuth20Constants.PARAM_STATE, + pendingReq.getPendingRequestId()); + redirectURI = addURLParameter(redirectURI, OAuth20Constants.PARAM_REDIRECT_URI, + pendingReq.getAuthURL() + eID4UConstants.HTTP_ENDPOINT_AP_CONSENT_RETURN); + + final String finalUrl = redirectURI; + httpResp.addHeader("Location", finalUrl); + Logger.debug("REDIRECT TO: " + finalUrl.toString()); + + //set session cookie, because eID4U AP from TUG maybe not support pendingReqIds on request level + CookieUtils.setCookie(httpReq, httpResp, + eID4UConstants.HTTP_TRANSACTION_COOKIE_NAME, + pendingReq.getPendingRequestId(), -1); + + //set user's bPK into pendingRequst because TUG AttributeProvider needs it + pendingReq.setRawDataToTransaction( + eID4UConstants.PROCESS_CONTEXT_USERS_BPK_EID4U_ATTRPROVIDER, + new BPKAttributeBuilder().build( + fakeOpenIDReq.getServiceProviderConfiguration(), + authData, + new SimpleStringAttributeGenerator())); + requestStoreage.storePendingRequest(pendingReq); + + } else + Logger.debug("No eID4U attributes found. Skip eID4U attribute collection"); + + } else + Logger.debug("No eIDAS Request found. Skip eID4U attribute collection"); + + } catch (Exception e) { + Logger.error("eID4U AttributeProvider communication FAILED.", e); + throw new TaskExecutionException(pendingReq, "eID4U AttributeProvider communication FAILED", e); + + } + + } + + private String mapReqAttributesIntoScopes(ImmutableAttributeMap reqEid4uAttrList) { + String result = StringUtils.EMPTY; + UnmodifiableIterator<ImmutableAttributeEntry<?>> it = reqEid4uAttrList.entrySet().iterator(); + while (it.hasNext()) { + ImmutableAttributeEntry<?> el = it.next(); + String scope = AttributeScopeMapper.getInstance().getTUGScopesForAttribute( + el.getKey().getNameUri().toString()); + + if (result.isEmpty()) + result = scope; + else + result += " " + scope; + + } + + return result; + } + +} diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/ReceiveAuthnResponseTask.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/ReceiveAuthnResponseTask.java index 1788facf0..274a23674 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/ReceiveAuthnResponseTask.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/ReceiveAuthnResponseTask.java @@ -57,11 +57,14 @@ public class ReceiveAuthnResponseTask extends AbstractAuthServletTask { ProtocolEngineI engine = SAMLEngineUtils.createSAMLEngine(eIDASMetadataProvider); //validate SAML token + //TODO: maybe add whitelist IAuthenticationResponse samlResp = engine.unmarshallResponseAndValidate(decSamlToken, request.getRemoteHost(), Constants.CONFIG_PROPS_SKEWTIME_BEFORE, Constants.CONFIG_PROPS_SKEWTIME_AFTER, - pendingReq.getAuthURL() + Constants.eIDAS_HTTP_ENDPOINT_METADATA); + pendingReq.getAuthURL() + Constants.eIDAS_HTTP_ENDPOINT_METADATA, + null, + false); if (samlResp.isEncrypted()) { Logger.info("Received encrypted eIDAS SAML-Response."); diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/ReceiveConsentForAddtionalAttributesTask.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/ReceiveConsentForAddtionalAttributesTask.java new file mode 100644 index 000000000..e878f8ab1 --- /dev/null +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/ReceiveConsentForAddtionalAttributesTask.java @@ -0,0 +1,238 @@ +package at.gv.egovernment.moa.id.auth.modules.eidas.tasks; + +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import java.util.Map; +import java.util.Map.Entry; + +import javax.net.ssl.SSLSocketFactory; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.io.IOUtils; +import org.apache.http.Header; +import org.apache.http.HttpHeaders; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.protocol.HttpClientContext; +import org.apache.http.client.utils.URIBuilder; +import org.apache.http.impl.client.CloseableHttpClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; +import at.gv.egiz.eaaf.core.exceptions.EAAFStorageException; +import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException; +import at.gv.egiz.eaaf.core.impl.idp.auth.modules.AbstractAuthServletTask; +import at.gv.egovernment.moa.id.auth.data.AuthenticationSessionWrapper; +import at.gv.egovernment.moa.id.auth.modules.eidas.eID4UConstants; +import at.gv.egovernment.moa.id.auth.modules.eidas.eid4u.utils.AttributeScopeMapper; +import at.gv.egovernment.moa.id.auth.modules.eidas.exceptions.eID4UAPException; +import at.gv.egovernment.moa.id.commons.api.AuthConfiguration; +import at.gv.egovernment.moa.id.commons.utils.HttpClientWithProxySupport; +import at.gv.egovernment.moa.id.protocols.eidas.EIDASData; +import at.gv.egovernment.moa.id.protocols.oauth20.OAuth20Constants; +import at.gv.egovernment.moa.id.util.CookieUtils; +import at.gv.egovernment.moa.id.util.SSLUtils; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.MiscUtil; + +@Component("ReceiveConsentForAddtionalAttributesTask") +public class ReceiveConsentForAddtionalAttributesTask extends AbstractAuthServletTask { + + private static final int HashMap = 0; + @Autowired private AuthConfiguration moaAuthConfig; + + @Override + public void execute(ExecutionContext context, HttpServletRequest httpReq, HttpServletResponse httpResp) + throws TaskExecutionException { + try{ + if (pendingReq instanceof EIDASData) { + EIDASData eidasReq = (EIDASData) pendingReq; + + //delete eID4U http Cookie with pendingRequestId + CookieUtils.deleteCookie(httpReq, httpResp, eID4UConstants.HTTP_TRANSACTION_COOKIE_NAME); + + String authCode = httpReq.getParameter(OAuth20Constants.RESPONSE_CODE); + if (MiscUtil.isEmpty(authCode)) { + Logger.info("Find NO OAuth2 authCode as http parameter 'code'. eID4U AP process stopping ... "); + throw new eID4UAPException("NO OAuth2 'authCode' to access AP", null); + + } + Logger.trace("Find OAuth2 'code' with: " + authCode); + + /* + * access backend service with authCode + * + */ + String tokenServiceURL = authConfig.getBasicConfiguration(eID4UConstants.CONFIG_PROPS_AP_AUTHTOKENSERVICE_URL); + String tokenServiceUsername = authConfig.getBasicConfiguration(eID4UConstants.CONFIG_PROPS_AP_AUTHTOKENSERVICE_USERNAME); + String tokenServicePassword = authConfig.getBasicConfiguration(eID4UConstants.CONFIG_PROPS_AP_AUTHTOKENSERVICE_PASSWORD); + + if (MiscUtil.isEmpty(tokenServiceURL)) { + Logger.info("NO TokenService URL in configuration for eID4U AP. "); + throw new eID4UAPException("NO TokenService URL in configuration for eID4U AP.", null); + + } + + //open http client + SSLSocketFactory sslFactory = SSLUtils.getSSLSocketFactory( + moaAuthConfig, + tokenServiceURL); + CloseableHttpClient httpClient = HttpClientWithProxySupport.getHttpClient( + sslFactory, + authConfig.getBasicMOAIDConfigurationBoolean(AuthConfiguration.PROP_KEY_OVS_SSL_HOSTNAME_VALIDATION, true)); + + //build request URL + URIBuilder uriBuilderToken = new URIBuilder(tokenServiceURL); + uriBuilderToken.addParameter(OAuth20Constants.PARAM_GRANT_TYPE, + authConfig.getBasicConfiguration( + eID4UConstants.CONFIG_PROPS_AP_AUTHTOKENSERVICE_PARAM_GRANTTYPE, + OAuth20Constants.PARAM_GRANT_TYPE_VALUE_AUTHORIZATION_CODE)); + uriBuilderToken.addParameter(OAuth20Constants.RESPONSE_CODE, authCode); + Logger.trace("Full eID4U Token-Service request URL: " + uriBuilderToken.build()); + + HttpGet httpGetToken = new HttpGet(uriBuilderToken.build()); + + HttpClientContext localContext = HttpClientContext.create(); + if (MiscUtil.isNotEmpty(tokenServiceUsername)) { + Logger.debug("Find AuthCredentials for eID4U AP. Injecting credentials ... "); + + //Raw work-around, because API solution does not work well + String auth = tokenServiceUsername.trim() + ":" + tokenServicePassword.trim(); + byte[] encodedAuth = Base64.getEncoder().encode(auth.getBytes(StandardCharsets.ISO_8859_1)); + String authHeader = "Basic " + new String(encodedAuth); + httpGetToken.setHeader(HttpHeaders.AUTHORIZATION, authHeader); + + //API solutuion +// HttpHost targetHost = new HttpHost(uriBuilderToken.build().toString()); +// AuthCache authCache = new BasicAuthCache(); +// authCache.put(targetHost, new BasicScheme()); +// +// CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); +// credentialsProvider.setCredentials(AuthScope.ANY, +// new UsernamePasswordCredentials(tokenServiceUsername.trim(), tokenServicePassword.trim())); +// localContext.setCredentialsProvider(credentialsProvider); +// localContext.setAuthCache(authCache); + + } + + //request tokenService + HttpResponse httpResultToken = httpClient.execute(httpGetToken, localContext); + + Logger.trace("Receive http StatusCode: " + httpResultToken.getStatusLine().getStatusCode() + + " from eID4U AP TokenService"); + + if (Logger.isTraceEnabled()) { + for (Header el : httpResultToken.getAllHeaders()) + Logger.trace("Resp. Headername:" + el.getName() + " Value:" + el.getValue()); + } + + if (httpResultToken.getStatusLine().getStatusCode() != 200) { + Logger.info("eID4U AP TokenService anwser with StatusCode:" + httpResultToken.getStatusLine().getStatusCode() + + " eID4U AP process stopping ... "); + if (httpResultToken.getEntity().getContent() != null) + Logger.trace("StatusMessage: " + IOUtils.toString(httpResultToken.getEntity().getContent(), "UTF-8")); + throw new eID4UAPException("eID4U AP TokenService return statusCode: " + httpResultToken.getStatusLine().getStatusCode(), null); + + } + + //parse AccessToken from TokenService response + JsonElement fullToken = new JsonParser().parse( + new InputStreamReader(httpResultToken.getEntity().getContent())); + Logger.trace("FullToken: " + fullToken.toString()); + String accessToken = fullToken.getAsJsonObject().get(OAuth20Constants.RESPONSE_ACCESS_TOKEN).getAsString(); + + + //call Attribute Provider to receice eID4U attributes from TUG + String attrProviderServiceURL = authConfig.getBasicConfiguration(eID4UConstants.CONFIG_PROPS_AP_DATASERVICE_URL); + if (MiscUtil.isEmpty(attrProviderServiceURL)) { + Logger.info("NO Attr.Provider Service URL in configuration for eID4U AP. "); + throw new eID4UAPException("NO Attr.Provider URL in configuration for eID4U AP.", null); + + } + + + URIBuilder uriBuilderAttrProv = new URIBuilder(attrProviderServiceURL); + HttpGet httpGetData = new HttpGet(uriBuilderAttrProv.build()); + + //encode and add token as header + String authHeader = "Bearer " + accessToken; + httpGetData.setHeader(HttpHeaders.AUTHORIZATION, authHeader); + + //get and add bPK as header + httpGetData.setHeader( + "X-PVP-BPK", + pendingReq.getRawData(eID4UConstants.PROCESS_CONTEXT_USERS_BPK_EID4U_ATTRPROVIDER, String.class)); + + if (Logger.isTraceEnabled()) { + for (Header el : httpGetData.getAllHeaders()) + Logger.trace("Req. Headername:" + el.getName() + " Value:" + el.getValue()); + } + + //request Attribute Provider + HttpResponse httpResultData = httpClient.execute(httpGetData); + + //parse response + Logger.trace("Receive http StatusCode: " + httpResultData.getStatusLine().getStatusCode() + + " from eID4U Attr.Provider Service"); + + if (Logger.isTraceEnabled()) { + for (Header el : httpResultData.getAllHeaders()) + Logger.trace("Resp. Headername:" + el.getName() + " Value:" + el.getValue()); + } + + if (httpResultData.getStatusLine().getStatusCode() != 200) { + Logger.info("eID4U Attr.Provider Service anwser with StatusCode:" + httpResultData.getStatusLine().getStatusCode() + + " eID4U AP process stopping ... "); + if (httpResultData.getEntity().getContent() != null) + Logger.trace("StatusMessage: " + IOUtils.toString(httpResultData.getEntity().getContent(), "UTF-8")); + + throw new eID4UAPException("eID4U Attr.Provider Service return statusCode: " + httpResultData.getStatusLine().getStatusCode(), null); + + } + + + //parse eID4U attributes from Attr.Provider service response + JsonElement fullAttrSet = new JsonParser().parse( + new InputStreamReader(httpResultData.getEntity().getContent())); + Logger.trace("FullAttrSet: " + fullAttrSet.toString()); + + //populate eID4U attributes + populateEid4uAttributes(fullAttrSet.getAsJsonObject()); + + //store pendingRequest + requestStoreage.storePendingRequest(pendingReq); + + + } else + Logger.debug("No eIDAS Request found. Skip eID4U attribute collection"); + + } catch (Exception e) { + Logger.error("IdentityLink generation for foreign person FAILED.", e); + throw new TaskExecutionException(pendingReq, "IdentityLink generation for foreign person FAILED.", e); + + } + + } + + private void populateEid4uAttributes(JsonObject jsonObject) throws EAAFStorageException { + try { + AuthenticationSessionWrapper session = pendingReq.getSessionData(AuthenticationSessionWrapper.class); + Map<String, Object> eID4UAttributes = AttributeScopeMapper.getInstance().populateEid4uAttributesFromTugResponse(jsonObject); + for (Entry<String, Object> el : eID4UAttributes.entrySet()) + session.setGenericDataToSession(el.getKey(), el.getValue()); + + } catch (EAAFStorageException e) { + Logger.warn("Can NOT inject authentication data into user object.", e); + throw e; + } + + } + +} |