use of com.tremolosecurity.idp.providers.oidc.model.OidcSessionState in project OpenUnison by TremoloSecurity.
the class TokenData method doPost.
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
if (request.getHeader("Accept") != null && request.getHeader("Accept").startsWith("application/json")) {
request.setAttribute("com.tremolosecurity.unison.proxy.noRedirectOnError", "com.tremolosecurity.unison.proxy.noRedirectOnError");
}
try {
String action = (String) request.getAttribute(IDP.ACTION_NAME);
if (action.contentEquals("completefed")) {
this.completeFederation(request, response);
} else if (action.equalsIgnoreCase("token")) {
String code = request.getParameter("code");
String clientID = request.getParameter("client_id");
String clientSecret = request.getParameter("client_secret");
String redirectURI = request.getParameter("redirect_uri");
String grantType = request.getParameter("grant_type");
String refreshToken = request.getParameter("refresh_token");
if (clientID == null) {
// this means that the clientid is in the Authorization header
String azHeader = request.getHeader("Authorization");
azHeader = azHeader.substring(azHeader.indexOf(' ') + 1).trim();
azHeader = new String(org.apache.commons.codec.binary.Base64.decodeBase64(azHeader));
clientID = azHeader.substring(0, azHeader.indexOf(':'));
clientSecret = azHeader.substring(azHeader.indexOf(':') + 1);
}
AuthController ac = (AuthController) request.getSession().getAttribute(ProxyConstants.AUTH_CTL);
UrlHolder holder = (UrlHolder) request.getAttribute(ProxyConstants.AUTOIDM_CFG);
holder.getApp().getCookieConfig().getTimeout();
if (refreshToken != null) {
try {
refreshToken(response, clientID, clientSecret, refreshToken, holder, request, ac.getAuthInfo());
} catch (Exception e1) {
logger.warn("Could not refresh token", e1);
AccessLog.log(AccessEvent.AzFail, holder.getApp(), (HttpServletRequest) request, ac.getAuthInfo(), "NONE");
response.sendError(401);
}
} else if (grantType.equalsIgnoreCase("urn:ietf:params:oauth:grant-type:token-exchange")) {
StsRequest stsRequest = new StsRequest();
stsRequest.setAudience(request.getParameter("audience"));
stsRequest.setDelegation(request.getParameter("actor_token") != null);
stsRequest.setImpersonation(!stsRequest.isDelegation());
stsRequest.setSubjectToken(request.getParameter("subject_token"));
stsRequest.setSubjectTokenType(request.getParameter("subject_token_type"));
stsRequest.setActorToken(request.getParameter("actor_token"));
stsRequest.setActorTokenType(request.getParameter("actor_token_type"));
stsRequest.setImpersonation(stsRequest.getActorToken() == null);
stsRequest.setDelegation(stsRequest.getActorToken() != null);
OpenIDConnectTrust trust = this.trusts.get(clientID);
if (trust == null) {
String errorMessage = new StringBuilder().append("Trust '").append(clientID).append("' not found").toString();
logger.warn(errorMessage);
throw new Exception(errorMessage);
}
if (!trust.isSts()) {
String errorMessage = new StringBuilder().append("Trust '").append(clientID).append("' not an sts").toString();
logger.warn(errorMessage);
response.sendError(401);
return;
}
if (stsRequest.isImpersonation()) {
stsImpersontion(request, response, clientID, ac, holder, stsRequest, trust);
} else {
if (!trust.isStsDelegation()) {
logger.warn(new StringBuilder().append("clientid '").append(clientID).append("' does not support delegation"));
response.sendError(403);
}
// validate the actor
X509Certificate sigCert = GlobalEntries.getGlobalEntries().getConfigManager().getCertificate(this.getJwtSigningKeyName());
if (sigCert == null) {
logger.error(new StringBuilder().append("JWT Signing Certificate '").append(this.getJwtSigningKeyName()).append("' does not exist").toString());
response.sendError(500);
return;
}
StringBuffer issuer = new StringBuffer();
// issuer.append(cfg.getAuthIdPPath()).append(this.idpName);
issuer.append(holder.getApp().getUrls().getUrl().get(0).getUri());
String issuerUrl = ProxyTools.getInstance().getFqdnUrl(issuer.toString(), request);
HttpSession session = request.getSession();
AuthInfo authData = ((AuthController) session.getAttribute(ProxyConstants.AUTH_CTL)).getAuthInfo();
TokenData actorTokenData = this.validateToken(stsRequest.getActorToken(), "actor_token", sigCert.getPublicKey(), issuerUrl, clientID, holder, request, authData, response, false);
if (actorTokenData == null) {
return;
}
String uidAttribute = this.getUidAttributeFromMap();
if (uidAttribute == null) {
logger.error(new StringBuilder().append("IdP ").append(holder.getApp().getName()).append(" does not have a sub attribute mapped to a user attribute").toString());
response.sendError(500);
return;
}
String authChainName = null;
AuthChainType actorAuthChain = null;
if (actorTokenData.amr != null) {
authChainName = this.getAmrToAuthChain().get(actorTokenData.amr);
if (authChainName != null) {
actorAuthChain = GlobalEntries.getGlobalEntries().getConfigManager().getAuthChains().get(authChainName);
}
}
AuthInfo actorAuth = this.jwtToAuthInfo(actorTokenData, uidAttribute, actorAuthChain, authChainName);
if (actorAuth == null) {
// don't think this can happen
logger.error("Could not create user auth object from jwt");
response.sendError(500);
return;
}
AzSys azSys = new AzSys();
if (!azSys.checkRules(actorAuth, GlobalEntries.getGlobalEntries().getConfigManager(), trust.getClientAzRules(), new HashMap<String, Object>())) {
AccessLog.log(AccessEvent.AzFail, holder.getApp(), request, actorAuth, new StringBuilder().append("client not authorized to exchange token for subject '").append(actorTokenData.subjectUid).append("'").toString());
response.sendError(403);
return;
}
if (!trust.getAllowedAudiences().contains(stsRequest.getAudience())) {
AccessLog.log(AccessEvent.AzFail, holder.getApp(), request, actorAuth, new StringBuilder().append("Audience '").append(stsRequest.getAudience()).append("' is not an authorized audience for sts '").append(trust.getTrustName()).append("'").toString());
response.sendError(403);
return;
}
OpenIDConnectTrust targetTrust = this.getTrusts().get(stsRequest.getAudience());
if (targetTrust == null) {
logger.warn(new StringBuilder().append("Audience '").append(stsRequest.getAudience()).append("' does not exist").toString());
response.sendError(404);
return;
}
TokenData subjectTokenData = this.validateToken(stsRequest.getSubjectToken(), "subject_token", sigCert.getPublicKey(), issuerUrl, null, holder, request, authData, response, true);
if (subjectTokenData == null) {
return;
}
authChainName = null;
actorAuthChain = null;
if (subjectTokenData.amr != null) {
authChainName = this.getAmrToAuthChain().get(subjectTokenData.amr);
if (authChainName != null) {
actorAuthChain = GlobalEntries.getGlobalEntries().getConfigManager().getAuthChains().get(authChainName);
}
}
AuthInfo subjectAuth = this.jwtToAuthInfo(subjectTokenData, uidAttribute, actorAuthChain, authChainName);
if (subjectAuth == null) {
// don't think this can happen
logger.error("Could not create user auth object from jwt");
response.sendError(500);
return;
}
if (!azSys.checkRules(subjectAuth, GlobalEntries.getGlobalEntries().getConfigManager(), trust.getSubjectAzRules(), new HashMap<String, Object>())) {
AccessLog.log(AccessEvent.AzFail, holder.getApp(), request, actorAuth, new StringBuilder().append("client not authorized to exchange token for subject '").append(subjectTokenData.subjectUid).append("'").toString());
response.sendError(403);
return;
}
OpenIDConnectAccessToken access = new OpenIDConnectAccessToken();
OidcSessionState oidcSession = this.createUserSession(request, stsRequest.getAudience(), holder, targetTrust, subjectAuth.getUserDN(), GlobalEntries.getGlobalEntries().getConfigManager(), access, UUID.randomUUID().toString(), subjectAuth.getAuthChain(), subjectTokenData.root, actorTokenData.root);
AccessLog.log(AccessEvent.AzSuccess, holder.getApp(), request, actorAuth, new StringBuilder().append("client '").append(trust.getTrustName()).append("' delegated to by '").append(subjectTokenData.subjectUid).append("', jti : '").append(access.getIdTokenId()).append("'").toString());
String idtoken = access.getId_token();
access.setRefresh_token(oidcSession.getRefreshToken());
Gson gson = new Gson();
String json = gson.toJson(access);
response.setContentType("application/json");
response.getOutputStream().write(json.getBytes("UTF-8"));
response.getOutputStream().flush();
if (logger.isDebugEnabled()) {
logger.debug("Token JSON : '" + json + "'");
}
}
} else if (grantType.equalsIgnoreCase("client_credentials")) {
clientCredentialsGrant(request, response, clientID, clientSecret, ac, holder);
} else {
completeUserLogin(request, response, code, clientID, clientSecret, holder, ac.getAuthInfo());
}
}
} catch (Throwable t) {
if (request.getHeader("Accept") != null && request.getHeader("Accept").startsWith("application/json")) {
response.sendError(500);
response.setContentType("application/json");
response.getWriter().print("{\"error\":\"invalid_request\"}");
logger.error("Sending JSON Error", t);
} else {
if (t instanceof ServletException) {
throw (ServletException) t;
} else if (t instanceof IOException) {
throw (IOException) t;
} else {
throw new ServletException("Error processing post", t);
}
}
}
}
use of com.tremolosecurity.idp.providers.oidc.model.OidcSessionState in project OpenUnison by TremoloSecurity.
the class TokenData method completeUserLogin.
private void completeUserLogin(HttpServletRequest request, HttpServletResponse response, String code, String clientID, String clientSecret, UrlHolder holder, AuthInfo authData) throws ServletException, IOException, MalformedURLException {
String lastMileToken = null;
try {
lastMileToken = this.inflate(code);
lastMileToken = new String(org.bouncycastle.util.encoders.Base64.encode(lastMileToken.getBytes("UTF-8")));
} catch (Exception e) {
throw new ServletException("Could not inflate code", e);
}
OpenIDConnectTrust trust = this.trusts.get(clientID);
if (!trust.isPublicEndpoint()) {
if (!clientSecret.equals(trust.getClientSecret())) {
AccessLog.log(AccessEvent.AzFail, holder.getApp(), (HttpServletRequest) request, authData, "NONE");
response.sendError(403);
return;
}
}
ConfigManager cfg = (ConfigManager) request.getAttribute(ProxyConstants.TREMOLO_CFG_OBJ);
SecretKey codeKey = cfg.getSecretKey(trust.getCodeLastmileKeyName());
com.tremolosecurity.lastmile.LastMile lmreq = new com.tremolosecurity.lastmile.LastMile();
try {
lmreq.loadLastMielToken(lastMileToken, codeKey);
} catch (Exception e) {
logger.warn("Could not decrypt code token", e);
response.sendError(403);
AccessLog.log(AccessEvent.AzFail, holder.getApp(), (HttpServletRequest) request, authData, "NONE");
return;
}
if (!lmreq.isValid()) {
response.sendError(403);
logger.warn("Could not validate code token");
AccessLog.log(AccessEvent.AzFail, holder.getApp(), (HttpServletRequest) request, authData, "NONE");
return;
}
Attribute dn = null;
Attribute scopes = null;
Attribute nonce = null;
Attribute authChainName = null;
for (Attribute attr : lmreq.getAttributes()) {
if (attr.getName().equalsIgnoreCase("dn")) {
dn = attr;
} else if (attr.getName().equalsIgnoreCase("scope")) {
scopes = attr;
} else if (attr.getName().equalsIgnoreCase("nonce")) {
nonce = attr;
} else if (attr.getName().equalsIgnoreCase("authChainName")) {
authChainName = attr;
}
}
ConfigManager cfgMgr = (ConfigManager) request.getAttribute(ProxyConstants.TREMOLO_CFG_OBJ);
DateTime now = new DateTime();
DateTime notBefore = now.minus(trust.getCodeTokenTimeToLive());
DateTime notAfter = now.plus(trust.getCodeTokenTimeToLive());
int authLevel = lmreq.getLoginLevel();
String authMethod = lmreq.getAuthChain();
try {
lmreq = new com.tremolosecurity.lastmile.LastMile(request.getRequestURI(), notBefore, notAfter, authLevel, authMethod);
} catch (URISyntaxException e) {
throw new ServletException("Could not request access token", e);
}
OpenIDConnectAccessToken access = new OpenIDConnectAccessToken();
/*
lmreq.getAttributes().add(new Attribute("dn",dn.getValues().get(0)));
SecretKey key = cfgMgr.getSecretKey(trust.getAccessLastmileKeyName());
String accessToken = null;
try {
accessToken = lmreq.generateLastMileToken(key);
} catch (Exception e) {
throw new ServletException("Could not generate access token",e);
}*/
String accessToken = null;
OidcSessionState oidcSession = createUserSession(request, clientID, holder, trust, dn.getValues().get(0), cfgMgr, access, (nonce != null ? nonce.getValues().get(0) : UUID.randomUUID().toString()), authChainName.getValues().get(0));
access.setRefresh_token(oidcSession.getRefreshToken());
Gson gson = new Gson();
String json = gson.toJson(access);
response.setContentType("application/json");
response.getOutputStream().write(json.getBytes("UTF-8"));
response.getOutputStream().flush();
if (logger.isDebugEnabled()) {
logger.debug("Token JSON : '" + json + "'");
}
AuthInfo remUser = new AuthInfo();
remUser.setUserDN(dn.getValues().get(0));
request.getSession().setAttribute(new StringBuilder().append("OIDC_SESSION_ID_").append(this.idpName).toString(), oidcSession.getSessionID());
AccessLog.log(AccessEvent.AzSuccess, holder.getApp(), (HttpServletRequest) request, remUser, "NONE");
}
use of com.tremolosecurity.idp.providers.oidc.model.OidcSessionState in project OpenUnison by TremoloSecurity.
the class TokenData method createUserSession.
public OidcSessionState createUserSession(HttpServletRequest request, String clientID, UrlHolder holder, OpenIDConnectTrust trust, String dn, ConfigManager cfgMgr, OpenIDConnectAccessToken access, String nonce, String authChain, JSONObject existingClaims, JSONObject actor) throws UnsupportedEncodingException, IOException, ServletException, MalformedURLException {
String sessionID = UUID.randomUUID().toString();
String encryptedSessionID = null;
try {
encryptedSessionID = this.encryptToken(this.sessionKeyName, new Gson(), sessionID);
} catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException e2) {
throw new ServletException("Could not generate session id", e2);
}
HashMap<String, String> extraAttribs = new HashMap<String, String>();
extraAttribs.put("session_id", encryptedSessionID);
String accessToken = null;
try {
accessToken = this.produceJWT(this.generateClaims(dn, cfgMgr, new URL(request.getRequestURL().toString()), trust, nonce, extraAttribs, request, authChain, existingClaims, actor), cfgMgr).getCompactSerialization();
} catch (JoseException | LDAPException | ProvisioningException e1) {
throw new ServletException("Could not generate jwt", e1);
}
access.setAccess_token(accessToken);
access.setExpires_in((int) (trust.getAccessTokenTimeToLive() / 1000));
try {
JwtClaims claims = this.generateClaims(dn, cfgMgr, new URL(request.getRequestURL().toString()), trust, nonce, null, request, authChain, existingClaims, actor);
access.setIdTokenId(claims.getJwtId());
access.setId_token(this.produceJWT(claims, cfgMgr).getCompactSerialization());
} catch (Exception e) {
throw new ServletException("Could not generate JWT", e);
}
access.setToken_type("Bearer");
OidcSessionState oidcSession = null;
try {
oidcSession = this.storeSession(access, holder.getApp(), trust.getCodeLastmileKeyName(), clientID, dn, sessionID);
if (!(this.sessionStore instanceof NoneBackend)) {
request.getSession().setAttribute(SessionManagerImpl.TREMOLO_EXTERNAL_SESSION, new OidcSessionExpires(oidcSession.getSessionID(), this.sessionStore));
}
} catch (Exception e) {
throw new ServletException("Could not store session", e);
}
LogoutUtil.insertFirstLogoutHandler(request, new ClearOidcSessionOnLogout(oidcSession, this));
return oidcSession;
}
use of com.tremolosecurity.idp.providers.oidc.model.OidcSessionState in project OpenUnison by TremoloSecurity.
the class TokenPostAuth method runAfterSuccessfulAuthentication.
@Override
public void runAfterSuccessfulAuthentication(HttpServletRequest req, HttpServletResponse resp, UrlHolder holder, AuthChainType act, RequestHolder reqHolder, AuthController actl, NextSys next) throws IOException, ServletException {
String subjectUid;
String amr;
HttpSession session = req.getSession();
AuthInfo authData = ((AuthController) session.getAttribute(ProxyConstants.AUTH_CTL)).getAuthInfo();
if (!azSys.checkRules(authData, GlobalEntries.getGlobalEntries().getConfigManager(), trust.getClientAzRules(), new HashMap<String, Object>())) {
AccessLog.log(AccessEvent.AzFail, holder.getApp(), req, authData, "client not authorized for token exchange");
resp.sendError(403);
return;
}
if (!trust.getAllowedAudiences().contains(stsRequest.getAudience())) {
AccessLog.log(AccessEvent.AzFail, holder.getApp(), req, authData, new StringBuilder().append("Audience '").append(stsRequest.getAudience()).append("' is not an authorized audience for sts '").append(trust.getTrustName()).append("'").toString());
resp.sendError(403);
return;
}
OpenIDConnectTrust targetTrust = idp.getTrusts().get(stsRequest.getAudience());
if (targetTrust == null) {
logger.warn(new StringBuilder().append("Audience '").append(stsRequest.getAudience()).append("' does not exist").toString());
resp.sendError(404);
return;
}
X509Certificate sigCert = GlobalEntries.getGlobalEntries().getConfigManager().getCertificate(idp.getJwtSigningKeyName());
if (sigCert == null) {
logger.error(new StringBuilder().append("JWT Signing Certificate '").append(idp.getJwtSigningKeyName()).append("' does not exist").toString());
resp.sendError(500);
return;
}
JsonWebSignature jws = new JsonWebSignature();
try {
jws.setCompactSerialization(stsRequest.getSubjectToken());
jws.setKey(sigCert.getPublicKey());
if (!jws.verifySignature()) {
AccessLog.log(AccessEvent.AzFail, holder.getApp(), req, authData, new StringBuilder().append("Invalid subject_token signature").toString());
resp.sendError(403);
return;
}
String json = jws.getPayload();
JSONObject obj = (JSONObject) new JSONParser().parse(json);
long exp = ((Long) obj.get("exp")) * 1000L;
long nbf = ((Long) obj.get("nbf")) * 1000L;
if (new DateTime(exp).isBeforeNow()) {
AccessLog.log(AccessEvent.AzFail, holder.getApp(), req, authData, new StringBuilder().append("subject_token has expired").toString());
resp.sendError(403);
return;
}
if (new DateTime(nbf).isAfterNow()) {
AccessLog.log(AccessEvent.AzFail, holder.getApp(), req, authData, new StringBuilder().append("subject_token is not yet valid").toString());
resp.sendError(403);
return;
}
StringBuffer issuer = new StringBuffer();
// issuer.append(cfg.getAuthIdPPath()).append(this.idpName);
issuer.append(holder.getApp().getUrls().getUrl().get(0).getUri());
String issuerUrl = ProxyTools.getInstance().getFqdnUrl(issuer.toString(), req);
if (!((String) obj.get("iss")).equals(issuerUrl)) {
AccessLog.log(AccessEvent.AzFail, holder.getApp(), req, authData, new StringBuilder().append("subject_token has an invalid issuer").toString());
resp.sendError(403);
return;
}
subjectUid = (String) obj.get("sub");
if (subjectUid == null) {
logger.error("Subject has no sub claim");
resp.sendError(422);
return;
}
JSONArray amrs = (JSONArray) obj.get("amr");
if (amrs == null) {
logger.warn("subject_token does not contain an amr claim");
resp.sendError(422);
return;
}
amr = (String) amrs.get(0);
} catch (JoseException | ParseException e) {
throw new ServletException("Could not verify subject JWT", e);
}
// load the user
String uidAttribute = idp.getUidAttributeFromMap();
if (uidAttribute == null) {
logger.error(new StringBuilder().append("IdP ").append(holder.getApp().getName()).append(" does not have a sub attribute mapped to a user attribute").toString());
resp.sendError(500);
return;
}
String authChainName = idp.getAmrToAuthChain().get(amr);
if (authChainName == null) {
logger.warn(new StringBuilder("subject_token amr '").append(amr).append("' does not map to any authentication chains").toString());
resp.sendError(422);
return;
}
AuthInfo subjectForAz = this.lookupUser(session, GlobalEntries.getGlobalEntries().getConfigManager().getMyVD(), uidAttribute, act, subjectUid, authChainName);
if (subjectForAz == null) {
logger.error(new StringBuilder().append("STS exchange for sub '").append(subjectUid).append("' failed because user not found"));
resp.sendError(422);
return;
}
// with a subject in hand, authorize that we're able to take care of
if (!azSys.checkRules(subjectForAz, GlobalEntries.getGlobalEntries().getConfigManager(), trust.getSubjectAzRules(), new HashMap<String, Object>())) {
AccessLog.log(AccessEvent.AzFail, holder.getApp(), req, authData, new StringBuilder().append("client not authorized to exchange token for subject '").append(subjectUid).append("'").toString());
resp.sendError(403);
return;
}
if (this.stsRequest.isImpersonation() && !trust.isStsImpersonation()) {
AccessLog.log(AccessEvent.AzFail, holder.getApp(), req, authData, new StringBuilder().append("client '").append(trust.getTrustName()).append("' authorized for impersonation").toString());
resp.sendError(403);
return;
}
if (this.stsRequest.isDelegation() && !trust.isStsDelegation()) {
AccessLog.log(AccessEvent.AzFail, holder.getApp(), req, authData, new StringBuilder().append("client '").append(trust.getTrustName()).append("' authorized for delegation").toString());
resp.sendError(403);
return;
}
OpenIDConnectAccessToken access = new OpenIDConnectAccessToken();
OidcSessionState oidcSession = idp.createUserSession(req, stsRequest.getAudience(), holder, targetTrust, subjectForAz.getUserDN(), GlobalEntries.getGlobalEntries().getConfigManager(), access, UUID.randomUUID().toString(), subjectForAz.getAuthChain());
if (this.stsRequest.isImpersonation()) {
AccessLog.log(AccessEvent.AzSuccess, holder.getApp(), req, authData, new StringBuilder().append("client '").append(trust.getTrustName()).append("' impersonating '").append(subjectUid).append("', jti : '").append(access.getIdTokenId()).append("'").toString());
}
String idtoken = access.getId_token();
access.setRefresh_token(oidcSession.getRefreshToken());
Gson gson = new Gson();
String json = gson.toJson(access);
resp.setContentType("application/json");
resp.getOutputStream().write(json.getBytes("UTF-8"));
resp.getOutputStream().flush();
if (logger.isDebugEnabled()) {
logger.debug("Token JSON : '" + json + "'");
}
}
use of com.tremolosecurity.idp.providers.oidc.model.OidcSessionState in project OpenUnison by TremoloSecurity.
the class DbOidcSessionStore method getSession.
@Override
public OidcSessionState getSession(String sessionId) throws Exception {
Session db = null;
try {
db = this.sessionFactory.openSession();
OidcDbSession dbSession = db.get(OidcDbSession.class, sessionId);
if (dbSession == null) {
return null;
}
OidcSessionState session = new OidcSessionState();
session.setClientID(dbSession.getClientID());
session.setEncryptedIdToken(dbSession.getEncryptedIdToken());
session.setEncryptedAccessToken(dbSession.getEncryptedAccessToken());
session.setExpires(new DateTime(dbSession.getExpires()));
session.setSessionID(dbSession.getSessionID());
session.setUserDN(dbSession.getUserDN());
session.setRefreshToken(dbSession.getRefreshToken());
return session;
} finally {
if (db != null) {
if (db.getTransaction() != null && db.getTransaction().isActive()) {
db.getTransaction().rollback();
}
db.close();
}
}
}
Aggregations