Commit 97a2210d authored by bimmel's avatar bimmel
Browse files

add callback url, better exceptions

parent 226b3009
......@@ -30,14 +30,8 @@ public class OidcRpConfigurationEntity extends AbstractBaseEntity {
@Column(name = "service_url", length = 1024)
private String serviceUrl;
@Column(name = "auth_url", length = 1024)
private String authUrl;
@Column(name = "token_endpoint", length = 1024)
private String tokenEndpoint;
@Column(name = "userinfo_endpoint", length = 1024)
private String userInfoEndpoint;
@Column(name = "callback_url", length = 1024)
private String callbackUrl;
public String getName() {
return name;
......@@ -47,30 +41,6 @@ public class OidcRpConfigurationEntity extends AbstractBaseEntity {
this.name = name;
}
public String getAuthUrl() {
return authUrl;
}
public void setAuthUrl(String authUrl) {
this.authUrl = authUrl;
}
public String getTokenEndpoint() {
return tokenEndpoint;
}
public void setTokenEndpoint(String tokenEndpoint) {
this.tokenEndpoint = tokenEndpoint;
}
public String getUserInfoEndpoint() {
return userInfoEndpoint;
}
public void setUserInfoEndpoint(String userInfoEndpoint) {
this.userInfoEndpoint = userInfoEndpoint;
}
public String getClientId() {
return clientId;
}
......@@ -111,4 +81,11 @@ public class OidcRpConfigurationEntity extends AbstractBaseEntity {
this.displayName = displayName;
}
public String getCallbackUrl() {
return callbackUrl;
}
public void setCallbackUrl(String callbackUrl) {
this.callbackUrl = callbackUrl;
}
}
......@@ -21,7 +21,7 @@
<property name="hibernate.cache.use_second_level_cache"
value="false" />
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.generate_statistics" value="true"/>
<property name="hibernate.generate_statistics" value="false"/>
</properties>
</persistence-unit>
......
......@@ -55,6 +55,9 @@ public class OidcClientCallbackServiceImpl implements OidcClientCallbackService
@Inject
private OidcRpFlowStateDao rpFlowStateDao;
@Inject
private OidcOpMetadataSingletonBean opMetadataBean;
@Override
public void callback(String uri) throws OidcAuthenticationException {
......@@ -76,11 +79,6 @@ public class OidcClientCallbackServiceImpl implements OidcClientCallbackService
OidcRpConfigurationEntity rpConfig = flowState.getRpConfiguration();
Issuer issuer = new Issuer(rpConfig.getServiceUrl());
OIDCProviderConfigurationRequest configRequest = new OIDCProviderConfigurationRequest(issuer);
HTTPResponse configResponse = configRequest.toHTTPRequest().send();
OIDCProviderMetadata opMetadata = OIDCProviderMetadata.parse(configResponse.getContentAsJSONObject());
AuthorizationCode code = successResponse.getAuthorizationCode();
flowState.setCode(code.getValue());
......@@ -92,24 +90,23 @@ public class OidcClientCallbackServiceImpl implements OidcClientCallbackService
ClientAuthentication clientAuth = new ClientSecretBasic(clientID, clientSecret);
// Make the token request
TokenRequest tokenRequest = new TokenRequest(opMetadata.getTokenEndpointURI(),
TokenRequest tokenRequest = new TokenRequest(opMetadataBean.getTokenEndpointURI(rpConfig),
clientAuth, codeGrant);
TokenResponse tokenResponse = OIDCTokenResponseParser.parse(tokenRequest.toHTTPRequest().send());
if (! response.indicatesSuccess()) {
throw new OidcAuthenticationException("got token error response: " + response.toErrorResponse());
if (! tokenResponse.indicatesSuccess()) {
throw new OidcAuthenticationException("got token error response: " + tokenResponse.toErrorResponse().getErrorObject().getDescription());
}
OIDCTokenResponse oidcTokenResponse = (OIDCTokenResponse) tokenResponse.toSuccessResponse();
JWT idToken = oidcTokenResponse.getOIDCTokens().getIDToken();
AccessToken accessToken = oidcTokenResponse.getOIDCTokens().getAccessToken();
RefreshToken refreshToken = oidcTokenResponse.getOIDCTokens().getRefreshToken();
BearerAccessToken bat = oidcTokenResponse.getOIDCTokens().getBearerAccessToken();
HTTPResponse httpResponse = new UserInfoRequest(
opMetadata.getUserInfoEndpointURI(), bat)
opMetadataBean.getUserInfoEndpointURI(rpConfig), bat)
.toHTTPRequest()
.send();
......
......@@ -11,6 +11,7 @@ import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import com.nimbusds.oauth2.sdk.AuthorizationRequest;
import com.nimbusds.oauth2.sdk.ParseException;
import com.nimbusds.oauth2.sdk.ResponseType;
import com.nimbusds.oauth2.sdk.Scope;
import com.nimbusds.oauth2.sdk.id.ClientID;
......@@ -36,16 +37,24 @@ public class OidcClientRedirectServiceImpl implements OidcClientRedirectService
@Inject
private OidcRpFlowStateDao rpFlowStateDao;
@Inject
private OidcOpMetadataSingletonBean opMetadataBean;
@Override
public void redirectClient(Long oidcRelyingPartyId, HttpServletResponse response) throws OidcAuthenticationException {
OidcRpConfigurationEntity rpConfig = rpConfigDao.findById(oidcRelyingPartyId);
if (rpConfig == null) {
throw new OidcAuthenticationException("relying party not configured");
}
try {
URI authzEndpoint = new URI(rpConfig.getAuthUrl());
URI authzEndpoint = opMetadataBean.getAuthorizationEndpointURI(rpConfig);
ClientID clientID = new ClientID(rpConfig.getClientId());
Scope scope = new Scope("openid", "profile", "email");
URI callback = new URI("https://bwidm.scc.kit.edu/rpoidc/callback");
URI callback = new URI(rpConfig.getCallbackUrl());
State state = new State();
AuthorizationRequest request = new AuthorizationRequest.Builder(
new ResponseType(ResponseType.Value.CODE), clientID)
......@@ -64,7 +73,7 @@ public class OidcClientRedirectServiceImpl implements OidcClientRedirectService
logger.info("Sending OIDC Client to uri: {}", requestURI);
response.sendRedirect(requestURI.toString());
} catch (URISyntaxException | IOException e) {
} catch (URISyntaxException | IOException | ParseException e) {
logger.warn("Exception while building oidc request and redirect: {}", e.getMessage());
throw new OidcAuthenticationException(e);
}
......
package edu.kit.scc.webreg.service.oidc.client;
import java.io.IOException;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import javax.ejb.Singleton;
import javax.inject.Inject;
import org.slf4j.Logger;
import com.nimbusds.oauth2.sdk.ParseException;
import com.nimbusds.oauth2.sdk.http.HTTPResponse;
import com.nimbusds.oauth2.sdk.id.Issuer;
import com.nimbusds.openid.connect.sdk.op.OIDCProviderConfigurationRequest;
import com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata;
import edu.kit.scc.webreg.entity.oidc.OidcRpConfigurationEntity;
@Singleton
public class OidcOpMetadataSingletonBean {
@Inject
private Logger logger;
private Map<OidcRpConfigurationEntity, OIDCProviderMetadata> metadataMap;
private Map<OidcRpConfigurationEntity, Long> expiryMap;
public OidcOpMetadataSingletonBean() {
metadataMap = new HashMap<OidcRpConfigurationEntity, OIDCProviderMetadata>();
expiryMap = new HashMap<OidcRpConfigurationEntity, Long>();
}
public URI getAuthorizationEndpointURI(OidcRpConfigurationEntity rpConfig) throws IOException, ParseException {
OIDCProviderMetadata opMetadata = getOpMetadata(rpConfig);
return opMetadata.getAuthorizationEndpointURI();
}
public URI getTokenEndpointURI(OidcRpConfigurationEntity rpConfig) throws IOException, ParseException {
OIDCProviderMetadata opMetadata = getOpMetadata(rpConfig);
return opMetadata.getTokenEndpointURI();
}
public URI getUserInfoEndpointURI(OidcRpConfigurationEntity rpConfig) throws IOException, ParseException {
OIDCProviderMetadata opMetadata = getOpMetadata(rpConfig);
return opMetadata.getUserInfoEndpointURI();
}
public OIDCProviderMetadata getOpMetadata(OidcRpConfigurationEntity rpConfig) throws IOException, ParseException {
OIDCProviderMetadata opMetadata;
Boolean expired = false;
synchronized (expiryMap) {
if (expiryMap.containsKey(rpConfig)) {
if ((System.currentTimeMillis() - expiryMap.get(rpConfig)) > 5 * 60 * 1000L) {
// metadata is more than 5 minutes old. Set to expired
expired = true;
}
}
else {
// metadata not loaded yet. Set to expired
expired = true;
}
}
if (expired) {
logger.debug("Reloading metadata for {}", rpConfig.getName());
Issuer issuer = new Issuer(rpConfig.getServiceUrl());
OIDCProviderConfigurationRequest configRequest = new OIDCProviderConfigurationRequest(issuer);
HTTPResponse configResponse = configRequest.toHTTPRequest().send();
opMetadata = OIDCProviderMetadata.parse(configResponse.getContentAsJSONObject());
synchronized (expiryMap) {
metadataMap.put(rpConfig, opMetadata);
expiryMap.put(rpConfig, System.currentTimeMillis());
}
}
else {
synchronized (expiryMap) {
opMetadata = metadataMap.get(rpConfig);
}
}
return opMetadata;
}
}
......@@ -26,8 +26,10 @@ import javax.inject.Inject;
import edu.kit.scc.webreg.entity.FederationEntity;
import edu.kit.scc.webreg.entity.SamlIdpMetadataEntity;
import edu.kit.scc.webreg.entity.SamlSpConfigurationEntity;
import edu.kit.scc.webreg.entity.oidc.OidcRpConfigurationEntity;
import edu.kit.scc.webreg.service.SamlIdpMetadataService;
import edu.kit.scc.webreg.service.SamlSpConfigurationService;
import edu.kit.scc.webreg.service.oidc.OidcRpConfigurationService;
import edu.kit.scc.webreg.service.saml.FederationSingletonBean;
import edu.kit.scc.webreg.session.SessionManager;
import edu.kit.scc.webreg.util.FacesMessageGenerator;
......@@ -47,6 +49,9 @@ public class DiscoveryLoginBean implements Serializable {
@Inject
private SamlSpConfigurationService spService;
@Inject
private OidcRpConfigurationService oidcRpService;
@Inject
private SessionManager sessionManager;
......@@ -58,6 +63,9 @@ public class DiscoveryLoginBean implements Serializable {
private FederationEntity selectedFederation;
private SamlIdpMetadataEntity selectedIdp;
private List<OidcRpConfigurationEntity> oidcRpList;
private OidcRpConfigurationEntity selectedOidcRp;
private String filter;
private Boolean initialized = false;
......@@ -114,12 +122,19 @@ public class DiscoveryLoginBean implements Serializable {
public void oidcLogin() {
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
sessionManager.setOidcRelyingPartyId(50080514L);
try {
externalContext.redirect("/rpoidc/login");
} catch (IOException e) {
messageGenerator.addErrorMessage("Ein Fehler ist aufgetreten",
e.toString());
if (selectedOidcRp != null) {
sessionManager.setOidcRelyingPartyId(selectedOidcRp.getId());
try {
externalContext.redirect("/rpoidc/login");
} catch (IOException e) {
messageGenerator.addErrorMessage("Ein Fehler ist aufgetreten",
e.toString());
}
}
else {
messageGenerator.addWarningMessage("Keine Auswahl getroffen",
"Bitte wählen Sie Ihre Heimatorganisation");
}
}
......@@ -189,4 +204,19 @@ public class DiscoveryLoginBean implements Serializable {
this.filter = filter;
}
public List<OidcRpConfigurationEntity> getOidcRpList() {
if (oidcRpList == null) {
oidcRpList = oidcRpService.findAll();
}
return oidcRpList;
}
public OidcRpConfigurationEntity getSelectedOidcRp() {
return selectedOidcRp;
}
public void setSelectedOidcRp(OidcRpConfigurationEntity selectedOidcRp) {
this.selectedOidcRp = selectedOidcRp;
}
}
/*******************************************************************************
* Copyright (c) 2014 Michael Simon.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*
* Contributors:
* Michael Simon - initial
******************************************************************************/
package edu.kit.scc.webreg.converter;
import javax.inject.Inject;
import javax.inject.Named;
import edu.kit.scc.webreg.entity.BaseEntity;
import edu.kit.scc.webreg.service.BaseService;
import edu.kit.scc.webreg.service.oidc.OidcRpConfigurationService;
@Named("oidcRpConfigurationConverter")
public class OidcRpConfigurationConverter extends AbstractConverter {
private static final long serialVersionUID = 1L;
@Inject
private OidcRpConfigurationService service;
@Override
protected BaseService<? extends BaseEntity<Long>, Long> getService() {
return service;
}
}
......@@ -71,7 +71,7 @@ public class OidcClientCallbackHandlerServlet implements Servlet {
try {
callbackService.callback(requestURL.toString());
} catch (OidcAuthenticationException e) {
throw new ServletException("Problems encountered");
throw new ServletException("Problems encountered: " + e.getMessage());
}
}
......
......@@ -64,7 +64,7 @@ public class OidcClientRedirectHandlerServlet implements Servlet {
try {
redirectService.redirectClient(session.getOidcRelyingPartyId(), response);
} catch (OidcAuthenticationException e) {
throw new ServletException("Problems encountered");
throw new ServletException("Problems encountered: " + e.getMessage());
}
}
......
......@@ -35,7 +35,7 @@
value="#{editOidcRpConfigurationBean.entity.name}" required="true" />
<bw:inputText id="displayNameField" label="#{messages.displayName}"
value="#{editOidcRpConfigurationBean.entity.displayName}" required="false" />
value="#{editOidcRpConfigurationBean.entity.displayName}" required="true" />
<bw:inputText id="clientIdField" label="#{messages.clientId}"
value="#{editOidcRpConfigurationBean.entity.clientId}" required="false" />
......@@ -47,16 +47,10 @@
value="#{editOidcRpConfigurationBean.entity.scopes}" required="false" />
<bw:inputText id="serviceUrlField" label="#{messages.serviceUrl}"
value="#{editOidcRpConfigurationBean.entity.serviceUrl}" required="false" />
value="#{editOidcRpConfigurationBean.entity.serviceUrl}" required="true" />
<bw:inputText id="authUrlField" label="#{messages.authUrl}"
value="#{editOidcRpConfigurationBean.entity.authUrl}" required="false" />
<bw:inputText id="tokenEndpointField" label="#{messages.tokenEndpoint}"
value="#{editOidcRpConfigurationBean.entity.tokenEndpoint}" required="false" />
<bw:inputText id="userInfoEndpointField" label="#{messages.userInfoEndpoint}"
value="#{editOidcRpConfigurationBean.entity.userInfoEndpoint}" required="false" />
<bw:inputText id="authUrlField" label="#{messages.callbackUrl}"
value="#{editOidcRpConfigurationBean.entity.callbackUrl}" required="true" />
</p:panelGrid>
<h:commandButton id="save" action="#{editOidcRpConfigurationBean.save}" value="#{messages.save}"/>
......
......@@ -49,6 +49,9 @@
<h:outputText value="#{messages.serviceUrl}:"/>
<h:outputText value="#{showOidcRpConfigurationBean.entity.serviceUrl}"/>
<h:outputText value="#{messages.callbackUrl}:"/>
<h:outputText value="#{showOidcRpConfigurationBean.entity.callbackUrl}"/>
</p:panelGrid>
<h:link outcome="edit-rp-config.xhtml" value="#{messages.edit}">
<f:param name="id" value="#{showOidcRpConfigurationBean.entity.id}"/>
......
......@@ -61,8 +61,18 @@
</p:panel>
<p:panel header="OIDC Test">
<h:panelGrid id="oidcBaseData" columns="2" style="margin-top: 8px;">
<p:outputLabel value="#{messages.home_org}:" for="idpBox" />
<p:selectOneListbox id="oidcBox" value="#{discoveryLoginBean.selectedOidcRp}" scrollHeight="120" style="width:300px;"
converter="#{oidcRpConfigurationConverter}">
<f:selectItems value="#{discoveryLoginBean.oidcRpList}"
var="rp" itemLabel="#{rp.displayName}" itemValue="#{rp}"/>
<p:ajax event="dblclick" listener="#{discoveryLoginBean.oidcLogin()}" update=":form" />
</p:selectOneListbox>
</h:panelGrid>
<p:commandButton id="oidcLogin" action="#{discoveryLoginBean.oidcLogin()}" value="#{messages.proceed}"
immediate="true"/>
update=":form"/>
</p:panel>
</h:form>
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment