Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.predic8.membrane.core.interceptor.oauth2server.LoginDialog2 Maven / Gradle / Ivy
/*
* Copyright 2019 predic8 GmbH, www.predic8.com
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.predic8.membrane.core.interceptor.oauth2server;
import com.floreysoft.jmte.Engine;
import com.floreysoft.jmte.ErrorHandler;
import com.floreysoft.jmte.message.ParseException;
import com.floreysoft.jmte.token.Token;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.predic8.membrane.core.Constants;
import com.predic8.membrane.core.Router;
import com.predic8.membrane.core.exchange.Exchange;
import com.predic8.membrane.core.http.Response;
import com.predic8.membrane.core.interceptor.Outcome;
import com.predic8.membrane.core.interceptor.authentication.session.AccountBlocker;
import com.predic8.membrane.core.interceptor.authentication.session.TokenProvider;
import com.predic8.membrane.core.interceptor.authentication.session.UserDataProvider;
import com.predic8.membrane.core.interceptor.oauth2.ConsentPageFile;
import com.predic8.membrane.core.interceptor.oauth2.OAuth2Util;
import com.predic8.membrane.core.interceptor.server.WebServerInterceptor;
import com.predic8.membrane.core.interceptor.session.Session;
import com.predic8.membrane.core.interceptor.session.SessionManager;
import com.predic8.membrane.core.resolver.ResolverMap;
import com.predic8.membrane.core.util.URI;
import com.predic8.membrane.core.util.URIFactory;
import com.predic8.membrane.core.util.URLParamUtil;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;
public class LoginDialog2 {
private static Logger log = LoggerFactory.getLogger(com.predic8.membrane.core.interceptor.authentication.session.LoginDialog.class.getName());
private String path, message;
private boolean exposeUserCredentialsToSession;
private URIFactory uriFactory;
private final UserDataProvider userDataProvider;
private final TokenProvider tokenProvider;
private final SessionManager sessionManager;
private final AccountBlocker accountBlocker;
private final WebServerInterceptor wsi;
public LoginDialog2(
UserDataProvider userDataProvider,
TokenProvider tokenProvider,
SessionManager sessionManager,
AccountBlocker accountBlocker,
String dialogLocation,
String path,
boolean exposeUserCredentialsToSession,
String message) {
this.path = path;
this.exposeUserCredentialsToSession = exposeUserCredentialsToSession;
this.userDataProvider = userDataProvider;
this.tokenProvider = tokenProvider;
this.sessionManager = sessionManager;
this.accountBlocker = accountBlocker;
this.message = message;
wsi = new WebServerInterceptor();
wsi.setDocBase(dialogLocation);
}
public void init(Router router) throws Exception {
uriFactory = router.getUriFactory();
wsi.init(router);
router.getResolverMap().resolve(ResolverMap.combine(router.getBaseLocation(), wsi.getDocBase(), "index.html")).close();
}
public boolean isLoginRequest(Exchange exc) {
URI uri = uriFactory.createWithoutException(exc.getRequest().getUri());
return uri.getPath().startsWith(path);
}
private void showPage(Exchange exc, int page, Object... params) throws Exception {
String target = StringUtils.defaultString(URLParamUtil.getParams(uriFactory, exc).get("target"));
exc.getDestinations().set(0, "/index.html");
wsi.handleRequest(exc);
Engine engine = new Engine();
engine.setErrorHandler(new ErrorHandler() {
@Override
public void error(String arg0, Token arg1, Map arg2) throws ParseException {
log.error(arg0);
}
@Override
public void error(String arg0, Token arg1) throws ParseException {
log.error(arg0);
}
});
Map pages = ImmutableMap
.builder()
.put(0, "login")
.put(1, "token")
.put(2, "consent")
.build();
Map model = new HashMap();
model.put("action", StringEscapeUtils.escapeXml(path)+ pages.get(page));
model.put("target", StringEscapeUtils.escapeXml(target));
model.put(pages.get(page).toString(),true);
for (int i = 0; i < params.length; i+=2)
model.put((String)params[i], params[i+1]);
exc.getResponse().setBodyContent(engine.transform(exc.getResponse().getBodyAsStringDecoded(), model).getBytes(Constants.UTF_8_CHARSET));
}
public void handleLoginRequest(Exchange exc) throws Exception {
Session s = sessionManager.getSession(exc);
String uri = exc.getRequest().getUri().substring( path.length() > 0 ? path.length()-1 : 0);
if (uri.indexOf('?') >= 0)
uri = uri.substring(0, uri.indexOf('?'));
exc.getDestinations().add(uri);
if (uri.equals("/logout")) {
if (s != null)
s.clear();
exc.setResponse(Response.redirect(path, false).body("").build());
} else if(uri.equals("/consent")){
if(exc.getRequest().getMethod().equals("POST"))
processConsentPageResult(exc, s);
else
showConsentPage(exc, s);
} else if (uri.equals("/login")) {
if (s == null || !s.isVerified()) {
if (exc.getRequest().getMethod().equals("POST")) {
Map userAttributes;
Map params = URLParamUtil.getParams(uriFactory, exc);
String username = params.get("username");
if (username == null) {
showPage(exc, 0, "error", "INVALID_PASSWORD");
return;
}
if (accountBlocker != null && accountBlocker.isBlocked(username)) {
showPage(exc, 0, "error", "ACCOUNT_BLOCKED");
return;
}
try {
userAttributes = userDataProvider.verify(params);
} catch (NoSuchElementException e) {
List params2 = Lists.newArrayList("error", "INVALID_PASSWORD");
if (accountBlocker != null) {
if (accountBlocker.fail(username))
params2.addAll(Lists.newArrayList("accountBlocked", "true"));
}
showPage(exc, 0, params2.toArray());
return;
} catch (Exception e) {
log.error("",e);
showPage(exc, 0, "error", "INTERNAL_SERVER_ERROR");
return;
}
if (exposeUserCredentialsToSession) {
for (Map.Entry param : params.entrySet())
if (!userAttributes.containsKey(param.getKey()))
userAttributes.put(param.getKey(), param.getValue());
}
if(tokenProvider != null)
showPage(exc, 1);
else {
String target = params.get("target");
if (StringUtils.isEmpty(target))
target = "/";
exc.setResponse(Response.redirectWithout300(target).build());
}
Map conv = s.get().entrySet().stream().collect(Collectors.toMap(k -> k.getKey(), v -> v.getValue().toString(), (m1,m2) -> m1));
if(tokenProvider != null)
tokenProvider.requestToken(conv);
s.get().keySet().stream().forEach(conv::remove);
conv.entrySet().stream().forEach(e -> s.put(e.getKey(),e.getValue()));
s.authorize(username);
} else {
showPage(exc, 0);
}
} else {
if (accountBlocker != null && accountBlocker.isBlocked(s.getUsername())) {
showPage(exc, 0, "error", "ACCOUNT_BLOCKED");
return;
}
if (exc.getRequest().getMethod().equals("POST")) {
String token = URLParamUtil.getParams(uriFactory, exc).get("token");
try {
if(tokenProvider != null)
tokenProvider.verifyToken(s.get().entrySet().stream().collect(Collectors.toMap(k -> k.getKey(), v -> v.getValue().toString(), (m1,m2) -> m1)), token);
} catch (NoSuchElementException e) {
List params = Lists.newArrayList("error", "INVALID_TOKEN");
if (accountBlocker != null)
if (accountBlocker.fail(s.getUsername()))
params.addAll(Lists.newArrayList("accountBlocked", "true"));
s.clear();
showPage(exc, 0, params.toArray());
return;
} catch (Exception e) {
log.error("",e);
s.clear();
showPage(exc, 0, "error", "INTERNAL_SERVER_ERROR");
return;
}
if (accountBlocker != null)
accountBlocker.unblock(s.getUsername());
String target = URLParamUtil.getParams(uriFactory, exc).get("target");
if (StringUtils.isEmpty(target))
target = "/";
if (this.message != null)
exc.setResponse(Response.redirectWithout300(target, message).build());
else
exc.setResponse(Response.redirectWithout300(target).build());
s.authorize(s.getUsername());
} else {
showPage(exc, 1);
}
}
} else {
wsi.handleRequest(exc);
}
}
private void processConsentPageResult(Exchange exc, Session s) throws Exception {
removeConsentPageDataFromSession(s);
putConsentInSession(exc, s);
redirectAfterConsent(exc);
}
private void removeConsentPageDataFromSession(Session s) {
if(s == null)
return;
synchronized (s) {
s.remove(ConsentPageFile.PRODUCT_NAME);
s.remove(ConsentPageFile.LOGO_URL);
s.remove(ConsentPageFile.SCOPE_DESCRIPTIONS);
s.remove(ConsentPageFile.CLAIM_DESCRIPTIONS);
}
}
private void redirectAfterConsent(Exchange exc) throws Exception {
String target = URLParamUtil.getParams(uriFactory, exc).get("target");
if (StringUtils.isEmpty(target))
target = "/";
exc.setResponse(Response.redirectWithout300(target).build());
}
private void putConsentInSession(Exchange exc, Session s) throws Exception {
if(s == null)
return;
Map params = URLParamUtil.getParams(uriFactory, exc);
String consentResult = "false";
if(params.get("consent").equals("Accept"))
consentResult = "true";
synchronized (s) {
s.put("consent", consentResult);
}
}
private void showConsentPage(Exchange exc, Session s) throws Exception {
if(s == null){
showPage(exc,2,ConsentPageFile.PRODUCT_NAME,null,ConsentPageFile.LOGO_URL,null,"scopes", null, "claims", null);
return;
}
synchronized(s) {
String productName = s.get(ConsentPageFile.PRODUCT_NAME);
String logoUrl = s.get(ConsentPageFile.LOGO_URL);
Map scopes = doubleStringArrayToMap(prepareScopesFromSession(s));
Map claims = doubleStringArrayToMap(prepareClaimsFromSession(s));
showPage(exc,2,ConsentPageFile.PRODUCT_NAME,productName,ConsentPageFile.LOGO_URL,logoUrl,"scopes", scopes, "claims", claims);
}
}
private Map doubleStringArrayToMap(String[] strings) {
HashMap result = new HashMap();
for(String string : strings) {
String[] str = string.split(" ");
for(int i = 2; i < str.length;i++)
str[1] += " " + str[i];
result.put(str[0], str[1]);
}
return result;
}
private String[] prepareClaimsFromSession(Session s) throws UnsupportedEncodingException {
return prepareStringArray(decodeClaimsFromSession(s));
}
private String[] prepareScopesFromSession(Session s) throws UnsupportedEncodingException {
return prepareStringArray(decodeScopesFromSession(s));
}
private String[] prepareStringArray(String[] array){
if(array[0].isEmpty())
return new String[0];
List result = new ArrayList();
for(int i = 0; i < array.length;i+=2)
result.add(array[i] + ": " + array[i+1]);
return result.toArray(new String[0]);
}
private String[] decodeClaimsFromSession(Session s) throws UnsupportedEncodingException {
if(s.get(ConsentPageFile.CLAIM_DESCRIPTIONS) != null) {
String[] claims = s.get(ConsentPageFile.CLAIM_DESCRIPTIONS).split(" ");
for (int i = 0; i < claims.length; i++)
claims[i] = OAuth2Util.urldecode(claims[i]);
return claims;
}
return new String[0];
}
private String[] decodeScopesFromSession(Session s) throws UnsupportedEncodingException {
if(s.get(ConsentPageFile.SCOPE_DESCRIPTIONS) != null) {
String[] scopes = s.get(ConsentPageFile.SCOPE_DESCRIPTIONS).split(" ");
for (int i = 0; i < scopes.length; i++)
scopes[i] = OAuth2Util.urldecode(scopes[i]);
return scopes;
}
return new String[0];
}
public Outcome redirectToLogin(Exchange exc) throws MalformedURLException, UnsupportedEncodingException {
exc.setResponse(Response.
redirect(path + "?target=" + URLEncoder.encode(exc.getOriginalRequestUri(), "UTF-8"), false).
dontCache().
body("").
build());
return Outcome.RETURN;
}
}