Java tutorial
/** * 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.pulsar.broker.authentication; import org.apache.commons.codec.digest.Crypt; import org.apache.commons.codec.digest.Md5Crypt; import org.apache.commons.lang3.StringUtils; import org.apache.pulsar.broker.ServiceConfiguration; import lombok.Cleanup; import javax.naming.AuthenticationException; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.util.*; public class AuthenticationProviderBasic implements AuthenticationProvider { private final static String HTTP_HEADER_NAME = "Authorization"; private final static String CONF_SYSTEM_PROPERTY_KEY = "pulsar.auth.basic.conf"; private Map<String, String> users; @Override public void close() throws IOException { // noop } @Override public void initialize(ServiceConfiguration config) throws IOException { File confFile = new File(System.getProperty(CONF_SYSTEM_PROPERTY_KEY)); if (!confFile.exists()) { throw new IOException("The password auth conf file does not exist"); } else if (!confFile.isFile()) { throw new IOException("The path is not a file"); } @Cleanup BufferedReader reader = new BufferedReader(new FileReader(confFile)); users = new HashMap<>(); for (String line : reader.lines().toArray(s -> new String[s])) { List<String> splitLine = Arrays.asList(line.split(":")); if (splitLine.size() != 2) { throw new IOException("The format of the password auth conf file is invalid"); } users.put(splitLine.get(0), splitLine.get(1)); } } @Override public String getAuthMethodName() { return "basic"; } @Override public String authenticate(AuthenticationDataSource authData) throws AuthenticationException { AuthParams authParams = new AuthParams(authData); String userId = authParams.getUserId(); String password = authParams.getPassword(); String msg = "Unknown user or invalid password"; if (users.get(userId) == null) { throw new AuthenticationException(msg); } String encryptedPassword = users.get(userId); // For md5 algorithm if ((users.get(userId).startsWith("$apr1"))) { List<String> splitEncryptedPassword = Arrays.asList(encryptedPassword.split("\\$")); if (splitEncryptedPassword.size() != 4 || !encryptedPassword .equals(Md5Crypt.apr1Crypt(password.getBytes(), splitEncryptedPassword.get(2)))) { throw new AuthenticationException(msg); } // For crypt algorithm } else if (!encryptedPassword.equals(Crypt.crypt(password.getBytes(), encryptedPassword.substring(0, 2)))) { throw new AuthenticationException(msg); } return userId; } private class AuthParams { private String userId; private String password; public AuthParams(AuthenticationDataSource authData) throws AuthenticationException { String authParams; if (authData.hasDataFromCommand()) { authParams = authData.getCommandData(); } else if (authData.hasDataFromHttp()) { String rawAuthToken = authData.getHttpHeader(HTTP_HEADER_NAME); // parsing and validation if (StringUtils.isBlank(rawAuthToken) || !rawAuthToken.toUpperCase().startsWith("BASIC ")) { throw new AuthenticationException("Authentication token has to be started with \"Basic \""); } String[] splitRawAuthToken = rawAuthToken.split(" "); if (splitRawAuthToken.length != 2) { throw new AuthenticationException("Base64 encoded token is not found"); } try { authParams = new String(Base64.getDecoder().decode(splitRawAuthToken[1])); } catch (Exception e) { throw new AuthenticationException("Base64 decoding is failure: " + e.getMessage()); } } else { throw new AuthenticationException("Authentication data source does not have data"); } String[] parsedAuthParams = authParams.split(":"); if (parsedAuthParams.length != 2) { throw new AuthenticationException("Base64 decoded params are invalid"); } userId = parsedAuthParams[0]; password = parsedAuthParams[1]; } public String getUserId() { return userId; } public String getPassword() { return password; } } }