blob: dd5a3d7cb0f822c17598010888e2facf77781ac1 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.dubbo.admin.common;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.admin.common.util.CoderUtil;
import org.apache.dubbo.admin.common.util.Constants;
import org.apache.dubbo.admin.model.domain.User;
import org.apache.dubbo.admin.service.UserService;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class LoginFilter implements Filter {
private static final Logger logger = LoggerFactory.getLogger(LoginFilter.class);
private static Pattern PARAMETER_PATTERN = Pattern.compile("(\\w+)=[\"]?([^,\"]+)[\"]?[,]?\\s*");
private static final String BASIC_CHALLENGE = "Basic";
private static final String DIGEST_CHALLENGE = "Digest";
private static final String CHALLENGE = BASIC_CHALLENGE;
private static final String REALM = User.REALM;
@Autowired
private UserService userService;
private String logout = "/api/dev/logout";
private String logoutCookie = "logout";
static Map<String, String> parseParameters(String query) {
Matcher matcher = PARAMETER_PATTERN.matcher(query);
Map<String, String> map = new HashMap<String, String>();
while (matcher.find()) {
String key = matcher.group(1);
String value = matcher.group(2);
map.put(key, value);
}
return map;
}
static byte[] readToBytes(InputStream in) throws IOException {
byte[] buf = new byte[in.available()];
in.read(buf);
return buf;
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest)request;
HttpServletResponse resp = (HttpServletResponse) response;
if (logger.isInfoEnabled()) {
logger.info("AuthorizationValve of uri: " + req.getRequestURI());
}
String uri = req.getRequestURI();
String contextPath = req.getContextPath();
if (contextPath != null && contextPath.length() > 0 && !"/".equals(contextPath)) {
uri = uri.substring(contextPath.length());
}
if (uri.equals(logout)) {
if (!isLogout(req)) {
setLogout(true, resp);
showLoginForm(resp);
} else {
setLogout(false, resp);
// resp.sendRedirect(contextPath == null || contextPath.length() == 0 ? "/" : contextPath);
}
return;
}
User user = null;
String authType = null;
String authorization = req.getHeader("Authorization");
if (authorization != null && authorization.length() > 0) {
int i = authorization.indexOf(' ');
if (i >= 0) {
authType = authorization.substring(0, i);
String authPrincipal = authorization.substring(i + 1);
if (BASIC_CHALLENGE.equalsIgnoreCase(authType)) {
user = loginByBase(authPrincipal);
} else if (DIGEST_CHALLENGE.equalsIgnoreCase(authType)) {
user = loginByDigest(authPrincipal, req);
}
}
}
if (user == null || user.getUsername() == null || user.getUsername().length() == 0) {
showLoginForm(resp);
return;
//pipelineContext.breakPipeline(1);
}
if (user != null && StringUtils.isNotEmpty(user.getUsername())) {
req.getSession().setAttribute("currentUser", user);
chain.doFilter(request, response);
}
}
@Override
public void destroy() {
}
private void showLoginForm(HttpServletResponse response) throws IOException {
if (DIGEST_CHALLENGE.equals(CHALLENGE)) {
response.setHeader("WWW-Authenticate", CHALLENGE + " realm=\"" + REALM + "\", qop=\"auth\", nonce=\""
+ UUID.randomUUID().toString().replace("-", "") + "\", opaque=\""
+ CoderUtil.MD5_32bit(REALM) + "\"");
} else {
response.setHeader("WWW-Authenticate", CHALLENGE + " realm=\"" + REALM + "\"");
}
response.setHeader("Cache-Control", "must-revalidate,no-cache,no-store");
response.setHeader("Content-Type", "text/html; charset=iso-8859-1");
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
private User getUser(String username) {
return userService.findUser(username);
}
private User loginByBase(String authorization) {
authorization = CoderUtil.decodeBase64(authorization);
int i = authorization.indexOf(':');
String username = authorization.substring(0, i);
if (username != null && username.length() > 0) {
String password = authorization.substring(i + 1);
if (password != null && password.length() > 0) {
String passwordDigest = CoderUtil.MD5_32bit(username + ":" + REALM + ":" + password);
User user = getUser(username);
if (user != null) {
String pwd = user.getPassword();
if (pwd != null && pwd.length() > 0) {
if (passwordDigest.equals(pwd)) {
return user;
}
}
}
}
}
return null;
}
private User loginByDigest(String value, HttpServletRequest request) throws IOException {
Map<String, String> params = parseParameters(value);
String username = params.get("username");
if (username != null && username.length() > 0) {
String passwordDigest = params.get("response");
if (passwordDigest != null && passwordDigest.length() > 0) {
User user = getUser(username);
if (user != null) {
String pwd = user.getPassword();
// A valid user, validate password
if (pwd != null && pwd.length() > 0) {
String uri = params.get("uri");
String nonce = params.get("nonce");
String nc = params.get("nc");
String cnonce = params.get("cnonce");
String qop = params.get("qop");
String method = request.getMethod();
String a1 = pwd;
String a2 = "auth-int".equals(qop)
? CoderUtil.MD5_32bit(method + ":" + uri + ":" + CoderUtil.MD5_32bit(readToBytes(request.getInputStream())))
: CoderUtil.MD5_32bit(method + ":" + uri);
String digest = "auth".equals(qop) || "auth-int".equals(qop)
? CoderUtil.MD5_32bit(a1 + ":" + nonce + ":" + nc + ":" + cnonce + ":" + qop + ":" + a2)
: CoderUtil.MD5_32bit(a1 + ":" + nonce + ":" + a2);
if (digest.equals(passwordDigest)) {
return user;
}
}
}
}
}
return null;
}
private boolean isLogout(HttpServletRequest request) {
Cookie[] cookies = request.getCookies();
if (cookies != null && cookies.length > 0) {
for (Cookie cookie : cookies) {
if (cookie != null && logoutCookie.equals(cookie.getName())) {
return "true".equals(cookie.getValue());
}
}
}
return false;
}
private void setLogout(boolean logoutValue, HttpServletResponse response) {
response.addCookie(new Cookie(logoutCookie, String.valueOf(logoutValue)));
}
}