Commit 8d64486d authored by michael.simon's avatar michael.simon
Browse files

create first login flow for oidc

parent 2ff3a4e8
......@@ -118,6 +118,12 @@
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.nimbusds</groupId>
<artifactId>oauth2-oidc-sdk</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
......
package edu.kit.scc.webreg.service.oidc;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import edu.kit.scc.webreg.service.saml.exc.OidcAuthenticationException;
import net.minidev.json.JSONObject;
public interface OidcOpLogin {
void registerAuthRequest(String realm, String responseType, String redirectUri, String scope, String state,
String nonce, String clientId, HttpServletRequest request, HttpServletResponse response)
throws IOException, OidcAuthenticationException ;
JSONObject serveToken(String realm, String grantType, String code, String redirectUri, HttpServletRequest request,
HttpServletResponse response) throws OidcAuthenticationException;
JSONObject serveUserInfo(String realm, String tokeType, String tokenId, HttpServletRequest request,
HttpServletResponse response) throws OidcAuthenticationException;
}
package edu.kit.scc.webreg.service.oidc;
import java.io.IOException;
import java.util.Date;
import java.util.UUID;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.JWSHeader;
import com.nimbusds.jose.crypto.MACSigner;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
import com.nimbusds.oauth2.sdk.Scope;
import com.nimbusds.oauth2.sdk.token.BearerAccessToken;
import com.nimbusds.openid.connect.sdk.OIDCTokenResponse;
import com.nimbusds.openid.connect.sdk.claims.UserInfo;
import com.nimbusds.openid.connect.sdk.token.OIDCTokens;
import edu.kit.scc.webreg.dao.UserDao;
import edu.kit.scc.webreg.dao.oidc.OidcFlowStateDao;
import edu.kit.scc.webreg.entity.UserEntity;
import edu.kit.scc.webreg.entity.oidc.OidcFlowStateEntity;
import edu.kit.scc.webreg.service.saml.exc.OidcAuthenticationException;
import edu.kit.scc.webreg.session.SessionManager;
import net.minidev.json.JSONObject;
@Stateless
public class OidcOpLoginImpl implements OidcOpLogin {
@Inject
private Logger logger;
@Inject
private OidcFlowStateDao flowStateDao;
@Inject
private UserDao userDao;
@Inject
private SessionManager session;
@Override
public void registerAuthRequest(String realm, String responseType,
String redirectUri, String scope,
String state, String nonce, String clientId,
HttpServletRequest request, HttpServletResponse response) throws IOException, OidcAuthenticationException {
if (session == null || session.getIdpId() == null || session.getSpId() == null) {
logger.debug("Client session from {} not established. In order to serve client must login. Sending to login page.",
request.getRemoteAddr());
OidcFlowStateEntity flowState = flowStateDao.createNew();
flowState.setNonce(nonce);
flowState.setState(state);
flowState.setClientId(clientId);
flowState.setResponseType(responseType);
flowState.setCode(UUID.randomUUID().toString());
flowState.setRedirectUri(redirectUri);
flowState.setValidUntil(new Date(System.currentTimeMillis() + (30L * 60L * 1000L)));
flowState = flowStateDao.persist(flowState);
session.setAuthnRequestId(flowState.getId());
session.setOriginalRequestPath("/oidc/realms/" + realm + "/protocol/openid-connect/auth");
response.sendRedirect("/welcome/index.xhtml");
return;
}
else {
if (session.getAuthnRequestId() == null) {
throw new OidcAuthenticationException("Authentication request id missing.");
}
OidcFlowStateEntity flowState = flowStateDao.findById(session.getAuthnRequestId());
if (flowState == null) {
throw new OidcAuthenticationException("Corresponding flow state not found.");
}
flowState.setValidUntil(new Date(System.currentTimeMillis() + (10L * 60L * 1000L)));
String red = flowState.getRedirectUri() + "?code=" + flowState.getCode() + "&state=" + flowState.getState();
logger.debug("Sending client to {}", red);
response.sendRedirect(red);
}
}
@Override
public JSONObject serveToken(String realm, String grantType,
String code, String redirectUri,
HttpServletRequest request, HttpServletResponse response) throws OidcAuthenticationException {
OidcFlowStateEntity flowState = flowStateDao.findByCode(code);
JWTClaimsSet claims = new JWTClaimsSet.Builder()
.expirationTime(new Date(System.currentTimeMillis() + (60L * 60L * 1000L)))
.issuer("https://bwidm.scc.kit.edu/oidc/realms/bwidm")
.claim("nonce", flowState.getNonce())
.audience(flowState.getClientId())
.build();
SignedJWT jwt;
try {
MACSigner macSigner = new MACSigner("qwertzuiopasdfghjklyxcvbnm12345678901234567890");
jwt = new SignedJWT(new JWSHeader(JWSAlgorithm.HS256), claims);
jwt.sign(macSigner);
} catch (JOSEException e) {
throw new OidcAuthenticationException(e);
}
BearerAccessToken bat = new BearerAccessToken(3600, new Scope("bwidm.scc.kit.edu"));
OIDCTokens tokens = new OIDCTokens(jwt, bat, null);
OIDCTokenResponse tokenResponse = new OIDCTokenResponse(tokens);
logger.debug("tokenResponse: " + tokenResponse.toJSONObject());
flowState.setAccessToken(bat.getValue());
flowState.setAccessTokenType("Bearer");
flowState.setValidUntil(new Date(System.currentTimeMillis() + bat.getLifetime()));
return tokenResponse.toJSONObject();
}
@Override
public JSONObject serveUserInfo(String realm, String tokeType, String tokenId,
HttpServletRequest request, HttpServletResponse response) throws OidcAuthenticationException {
if (session.getUserId() == null) {
throw new OidcAuthenticationException("No UserId set in session. Cannot continue");
}
UserEntity user = userDao.findById(session.getUserId());
OidcFlowStateEntity flowState = flowStateDao.findByAccessToken(tokenId, tokeType);
if (flowState == null) {
throw new OidcAuthenticationException("No flow state found for token.");
}
JWTClaimsSet claims = new JWTClaimsSet.Builder()
.subject(user.getEppn())
.claim("mail", user.getEmail())
.build();
UserInfo userInfo = new UserInfo(claims);
logger.debug("userInfo Response: " + userInfo.toJSONObject());
return userInfo.toJSONObject();
}
}
/*******************************************************************************
* 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.service.saml.exc;
import java.io.Serializable;
public class OidcAuthenticationException extends Exception implements Serializable {
private static final long serialVersionUID = 1L;
public OidcAuthenticationException(String msg) {
super(msg);
}
public OidcAuthenticationException(String msg, Throwable t) {
super(msg, t);
}
public OidcAuthenticationException(Throwable t) {
super(t);
}
}
package edu.kit.scc.webreg.oauth;
import java.io.IOException;
import java.util.Map.Entry;
import java.util.UUID;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
......@@ -13,13 +11,14 @@ import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import org.slf4j.Logger;
import edu.kit.scc.webreg.service.oidc.OidcOpLogin;
import edu.kit.scc.webreg.service.saml.exc.OidcAuthenticationException;
@Path("/realms")
public class OidcAuthorizationController {
@Inject
private Logger logger;
private OidcOpLogin opLogin;
@GET
@Path("/{realm}/protocol/openid-connect/auth")
......@@ -27,18 +26,8 @@ public class OidcAuthorizationController {
@QueryParam("redirect_uri") String redirectUri, @QueryParam("scope") String scope,
@QueryParam("state") String state, @QueryParam("nonce") String nonce, @QueryParam("client_id") String clientId,
@Context HttpServletRequest request, @Context HttpServletResponse response)
throws IOException {
throws IOException, OidcAuthenticationException {
logger.debug("processing {} with redirect to {}", responseType, redirectUri);
logger.debug("red: {}", request.getParameter("redirect_uri"));
for (Entry<String, String[]> e : request.getParameterMap().entrySet()) {
for (String s : e.getValue())
logger.debug("param: {} value: {}", e.getKey(), s);
}
String red = redirectUri + "?code=" + UUID.randomUUID().toString() + "&state=" + state;
logger.debug("Sending client to {}", red);
response.sendRedirect(red);
opLogin.registerAuthRequest(realm, responseType, redirectUri, scope, state, nonce, clientId, request, response);
}
}
......@@ -19,12 +19,14 @@ import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.JWSHeader;
import com.nimbusds.jose.crypto.MACSigner;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.PlainJWT;
import com.nimbusds.jwt.SignedJWT;
import com.nimbusds.oauth2.sdk.Scope;
import com.nimbusds.oauth2.sdk.token.BearerAccessToken;
import com.nimbusds.openid.connect.sdk.OIDCTokenResponse;
import com.nimbusds.openid.connect.sdk.token.OIDCTokens;
import edu.kit.scc.webreg.service.oidc.OidcOpLogin;
import net.minidev.json.JSONObject;
@Path("/realms")
......@@ -33,6 +35,9 @@ public class OidcTokenController {
@Inject
private Logger logger;
@Inject
private OidcOpLogin opLogin;
@POST
@Path("/{realm}/protocol/openid-connect/token")
@Produces(MediaType.APPLICATION_JSON)
......@@ -43,24 +48,7 @@ public class OidcTokenController {
logger.debug("Post token called for {} with code {} and grant_type {}", realm, code, grantType);
JWTClaimsSet claims = new JWTClaimsSet.Builder()
.subject("ls1947@kit.edu")
.expirationTime(new Date(System.currentTimeMillis() + (60L * 60L * 1000L)))
.claim("http://bwidm.scc.kit.edu/is_shibboleth", true)
.build();
MACSigner macSigner = new MACSigner("qwertzuiopasdfghjklyxcvbnm12345678901234567890");
SignedJWT jwt = new SignedJWT(new JWSHeader(JWSAlgorithm.HS256), claims);
jwt.sign(macSigner);
BearerAccessToken bat = new BearerAccessToken(3600, new Scope("bwidm.scc.kit.edu"));
OIDCTokens tokens = new OIDCTokens(jwt, bat, null);
OIDCTokenResponse tokenResponse = new OIDCTokenResponse(tokens);
logger.debug("tokenResponse: " + tokenResponse.toJSONObject());
return tokenResponse.toJSONObject();
return opLogin.serveToken(realm, grantType, code, redirectUri, request, response);
}
}
package edu.kit.scc.webreg.oauth;
import java.io.IOException;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
......@@ -14,20 +12,36 @@ import javax.ws.rs.core.MediaType;
import org.slf4j.Logger;
import edu.kit.scc.webreg.service.oidc.OidcOpLogin;
import edu.kit.scc.webreg.service.saml.exc.OidcAuthenticationException;
import net.minidev.json.JSONObject;
@Path("/realms")
public class OidcUserinfoController {
@Inject
private Logger logger;
@Inject
private OidcOpLogin opLogin;
@GET
@Path("/{realm}/protocol/openid-connect/userinfo")
@Produces(MediaType.APPLICATION_JSON)
public void userinfo(@PathParam("realm") String realm,
public JSONObject userinfo(@PathParam("realm") String realm,
@Context HttpServletRequest request, @Context HttpServletResponse response)
throws IOException {
throws OidcAuthenticationException {
logger.debug("userinfo called for {}", realm);
String authHeader = request.getHeader("Authorization");
String[] authHeaders = authHeader.split(" ", 2);
if (authHeaders.length == 2) {
logger.debug("Authorization header: {} type: {}", authHeaders[1], authHeaders[0]);
return opLogin.serveUserInfo(realm, authHeaders[0], authHeaders[1], request, response);
}
return null;
}
}
......@@ -65,6 +65,8 @@ public class OidcWellknownController {
metadata.setScopes(new Scope("openid", "profile", "email"));
metadata.setClaims(Arrays.asList(new String[] { "sub", "iss", "aud", "mail", "name" }));
if (logger.isTraceEnabled())
logger.trace(metadata.toJSONObject().toString());
......
package edu.kit.scc.webreg.oauth;
import java.io.IOException;
import java.util.Date;
import javax.inject.Inject;
import javax.inject.Named;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import com.nimbusds.jwt.JWT;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.PlainJWT;
import com.nimbusds.oauth2.sdk.AccessTokenResponse;
import com.nimbusds.oauth2.sdk.Scope;
import com.nimbusds.oauth2.sdk.token.BearerAccessToken;
import com.nimbusds.oauth2.sdk.token.Tokens;
import com.nimbusds.openid.connect.sdk.OIDCTokenResponse;
import com.nimbusds.openid.connect.sdk.token.OIDCTokens;
import edu.kit.scc.webreg.entity.UserEntity;
import edu.kit.scc.webreg.service.UserService;
import edu.kit.scc.webreg.session.SessionManager;
import net.minidev.json.JSONObject;
@Named
@WebServlet(urlPatterns = {"/oauth/token"})
public class TokenHandlerServlet implements Servlet {
@Inject
private Logger logger;
@Inject
private SessionManager session;
@Inject
private UserService userService;
@Override
public void init(ServletConfig config) throws ServletException {
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse)
throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
if (session == null || (! session.isLoggedIn())) {
logger.debug("Client session from {} not logged in. Sending client back to welcome page",
request.getRemoteAddr());
response.sendRedirect("/welcome/index.xhtml");
return;
}
UserEntity user = userService.findById(session.getUserId());
logger.debug("User {} ({}) loaded", user.getId(), user.getEppn());
JWTClaimsSet claims = new JWTClaimsSet.Builder()
.subject("" + session.getUserId())
.expirationTime(new Date(System.currentTimeMillis() + (60L * 60L * 1000L)))
.claim("http://bwidm.scc.kit.edu/is_shibboleth", true)
.build();
JWT jwt = new PlainJWT(claims);
BearerAccessToken bat = new BearerAccessToken(3600, new Scope("bwidm.scc.kit.edu"));
OIDCTokens tokens = new OIDCTokens(jwt, bat, null);
OIDCTokenResponse tokenResponse = new OIDCTokenResponse(tokens);
JSONObject jsonObject = tokenResponse.toJSONObject();
jsonObject.writeJSONString(response.getWriter());
}
@Override
public void destroy() {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public String getServletInfo() {
return null;
}
}
Markdown is supported
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