blob: c7c4997f18941154d5dc2da4f67647257e7aedb9 [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.cloudstack.auth;
import javax.inject.Inject;
import com.cloud.exception.CloudTwoFactorAuthenticationException;
import com.cloud.utils.exception.CloudRuntimeException;
import de.taimos.totp.TOTP;
import com.cloud.user.UserAccount;
import org.apache.commons.codec.binary.Base32;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringUtils;
import com.cloud.user.dao.UserAccountDao;
import com.cloud.utils.component.AdapterBase;
import java.security.SecureRandom;
public class TotpUserTwoFactorAuthenticator extends AdapterBase implements UserTwoFactorAuthenticator {
@Inject
private UserAccountDao _userAccountDao;
@Override
public String getName() {
return "totp";
}
@Override
public String getDescription() {
return "TOTP user two factor authentication provider Plugin";
}
@Override
public void check2FA(String code, UserAccount userAccount) throws CloudTwoFactorAuthenticationException {
String expectedCode = get2FACode(get2FAKey(userAccount));
if (expectedCode.equals(code)) {
logger.info("2FA matches user's input");
return;
}
throw new CloudTwoFactorAuthenticationException("two-factor authentication code provided is invalid");
}
private String get2FAKey(UserAccount userAccount) {
return userAccount.getKeyFor2fa();
}
private String get2FACode(String secretKey) {
Base32 base32 = new Base32();
byte[] bytes = base32.decode(secretKey);
String hexKey = Hex.encodeHexString(bytes);
return TOTP.getOTP(hexKey);
}
@Override
public String setup2FAKey(UserAccount userAccount) {
if (StringUtils.isNotEmpty(userAccount.getKeyFor2fa())) {
throw new CloudRuntimeException(String.format("2FA key is already setup for the user account %s", userAccount.getAccountName()));
}
SecureRandom random = new SecureRandom();
byte[] bytes = new byte[20];
random.nextBytes(bytes);
Base32 base32 = new Base32();
String key = base32.encodeToString(bytes);
userAccount.setKeyFor2fa(key);
return key;
}
}