|
|
@ -14,6 +14,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
package org.opendaylight.aaa.shiro.idm;
|
|
|
|
package org.opendaylight.aaa.shiro.idm;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import org.apache.shiro.crypto.hash.Md5Hash;
|
|
|
|
|
|
|
|
import org.immutables.value.internal.$processor$.meta.$ValueMirrors;
|
|
|
|
import org.opendaylight.aaa.AAAShiroProvider;
|
|
|
|
import org.opendaylight.aaa.AAAShiroProvider;
|
|
|
|
import org.opendaylight.aaa.api.IDMStoreException;
|
|
|
|
import org.opendaylight.aaa.api.IDMStoreException;
|
|
|
|
import org.opendaylight.aaa.api.model.IDMError;
|
|
|
|
import org.opendaylight.aaa.api.model.IDMError;
|
|
|
@ -21,42 +23,36 @@ import org.opendaylight.aaa.api.model.User;
|
|
|
|
import org.opendaylight.aaa.api.model.Users;
|
|
|
|
import org.opendaylight.aaa.api.model.Users;
|
|
|
|
import org.slf4j.Logger;
|
|
|
|
import org.slf4j.Logger;
|
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
|
|
|
|
import sun.security.provider.MD5;
|
|
|
|
|
|
|
|
|
|
|
|
import javax.ws.rs.Consumes;
|
|
|
|
import javax.ws.rs.*;
|
|
|
|
import javax.ws.rs.DELETE;
|
|
|
|
|
|
|
|
import javax.ws.rs.GET;
|
|
|
|
|
|
|
|
import javax.ws.rs.POST;
|
|
|
|
|
|
|
|
import javax.ws.rs.PUT;
|
|
|
|
|
|
|
|
import javax.ws.rs.Path;
|
|
|
|
|
|
|
|
import javax.ws.rs.PathParam;
|
|
|
|
|
|
|
|
import javax.ws.rs.Produces;
|
|
|
|
|
|
|
|
import javax.ws.rs.core.Context;
|
|
|
|
import javax.ws.rs.core.Context;
|
|
|
|
import javax.ws.rs.core.Response;
|
|
|
|
import javax.ws.rs.core.Response;
|
|
|
|
import javax.ws.rs.core.UriInfo;
|
|
|
|
import javax.ws.rs.core.UriInfo;
|
|
|
|
import java.util.Collection;
|
|
|
|
import java.util.Collection;
|
|
|
|
|
|
|
|
import java.util.Objects;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* @author Dong Xiancun
|
|
|
|
* @author Dong Xiancun
|
|
|
|
*
|
|
|
|
* <p>
|
|
|
|
* REST application used to manipulate the H2 database users table. The REST
|
|
|
|
* REST application used to manipulate the H2 database users table. The REST
|
|
|
|
* endpoint is <code>/auth/v1/users</code>.
|
|
|
|
* endpoint is <code>/auth/v1/users</code>.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* <p>
|
|
|
|
* <p>
|
|
|
|
* A wrapper script called <code>idmtool</code> is provided to manipulate AAA
|
|
|
|
* A wrapper script called <code>idmtool</code> is provided to manipulate AAA
|
|
|
|
* data.
|
|
|
|
* data.
|
|
|
|
*
|
|
|
|
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
@Path("/v1/users")
|
|
|
|
@Path("/v1/users")
|
|
|
|
public class UserHandler {
|
|
|
|
public class UserHandler {
|
|
|
|
|
|
|
|
|
|
|
|
private static final Logger LOG = LoggerFactory.getLogger(UserHandler.class);
|
|
|
|
private static final Logger LOG = LoggerFactory.getLogger(UserHandler.class);
|
|
|
|
|
|
|
|
private static final String PW_PATTERN = "/^(?![0-9]+$)(?![a-z]+$)(?![A-Z]+$)(?!([^(0-9a-zA-Z)])+$).{8,}$/";
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* If a user is created through the <code>/auth/v1/users</code> rest
|
|
|
|
* If a user is created through the <code>/auth/v1/users</code> rest
|
|
|
|
* endpoint without a password, the default password is assigned to the
|
|
|
|
* endpoint without a password, the default password is assigned to the
|
|
|
|
* user.
|
|
|
|
* user.
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
private static final String DEFAULT_PWD = "changeme";
|
|
|
|
private static final String DEFAULT_PWD = "changeme@10086";
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* When an HTTP GET is performed on <code>/auth/v1/users</code>, the
|
|
|
|
* When an HTTP GET is performed on <code>/auth/v1/users</code>, the
|
|
|
@ -113,10 +109,9 @@ public class UserHandler {
|
|
|
|
* Extracts the user represented by <code>id</code>. The password and salt
|
|
|
|
* Extracts the user represented by <code>id</code>. The password and salt
|
|
|
|
* fields are redacted for security reasons.
|
|
|
|
* fields are redacted for security reasons.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @param id
|
|
|
|
* @param id the unique id of representing the user account
|
|
|
|
* the unique id of representing the user account
|
|
|
|
|
|
|
|
* @return A response with the user information, or internal error if one
|
|
|
|
* @return A response with the user information, or internal error if one
|
|
|
|
* occurs
|
|
|
|
* occurs
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
@GET
|
|
|
|
@GET
|
|
|
|
@Path("/{id}")
|
|
|
|
@Path("/{id}")
|
|
|
@ -154,10 +149,8 @@ public class UserHandler {
|
|
|
|
* If a password is not provided, please ensure you change the default
|
|
|
|
* If a password is not provided, please ensure you change the default
|
|
|
|
* password ASAP for security reasons!
|
|
|
|
* password ASAP for security reasons!
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @param info
|
|
|
|
* @param info passed from Jersey
|
|
|
|
* passed from Jersey
|
|
|
|
* @param user the user defined in the JSON payload
|
|
|
|
* @param user
|
|
|
|
|
|
|
|
* the user defined in the JSON payload
|
|
|
|
|
|
|
|
* @return A response stating success or failure of user creation
|
|
|
|
* @return A response stating success or failure of user creation
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
@POST
|
|
|
|
@POST
|
|
|
@ -221,14 +214,12 @@ public class UserHandler {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// TODO add a check on email format here.
|
|
|
|
// TODO add a check on email format here.
|
|
|
|
|
|
|
|
|
|
|
|
// The "password" field is optional and defaults to "changeme".
|
|
|
|
// The "password" field is optional and defaults to "changeme@10086".
|
|
|
|
final String userPassword = user.getPassword();
|
|
|
|
final String userPassword = user.getPassword();
|
|
|
|
if (userPassword == null) {
|
|
|
|
Response response = checkPasswordError(userPassword);
|
|
|
|
user.setPassword(DEFAULT_PWD);
|
|
|
|
if (response.getStatus() != 200) {
|
|
|
|
} else if (userPassword.length() > IdmLightApplication.MAX_FIELD_LEN) {
|
|
|
|
return response;
|
|
|
|
return providedFieldTooLong("password", IdmLightApplication.MAX_FIELD_LEN);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
// At this point, fields have been properly verified. Create the
|
|
|
|
// At this point, fields have been properly verified. Create the
|
|
|
|
// user account
|
|
|
|
// user account
|
|
|
@ -245,15 +236,28 @@ public class UserHandler {
|
|
|
|
return Response.status(201).entity(user).build();
|
|
|
|
return Response.status(201).entity(user).build();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private Response checkPasswordError(String userPassword) {
|
|
|
|
|
|
|
|
if (Objects.isNull(userPassword)) {
|
|
|
|
|
|
|
|
return providePasswordError("密码不能为空。");
|
|
|
|
|
|
|
|
} else if (userPassword.length() > IdmLightApplication.MAX_FIELD_LEN) {
|
|
|
|
|
|
|
|
return providePasswordError("密码的最大长度不能超过256个字节。");
|
|
|
|
|
|
|
|
} else if (userPassword.length() < IdmLightApplication.MIN_PASSWORD_LEN) {
|
|
|
|
|
|
|
|
return providePasswordError("密码的长度不能低于8个自己");
|
|
|
|
|
|
|
|
} else if (!userPassword.matches(PW_PATTERN)) {
|
|
|
|
|
|
|
|
return providePasswordError("密码必须包含大写字母、小写字母、特殊字符、数字中两种或多种组合");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return Response.status(200).build();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private Response providePasswordError(String s) {
|
|
|
|
|
|
|
|
return new IDMError(407, s).response();
|
|
|
|
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* REST endpoint to update a user account.
|
|
|
|
* REST endpoint to update a user account.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @param info
|
|
|
|
* @param info passed from Jersey
|
|
|
|
* passed from Jersey
|
|
|
|
* @param user the user defined in the JSON payload
|
|
|
|
* @param user
|
|
|
|
* @param id the unique id for the user that will be updated
|
|
|
|
* the user defined in the JSON payload
|
|
|
|
|
|
|
|
* @param id
|
|
|
|
|
|
|
|
* the unique id for the user that will be updated
|
|
|
|
|
|
|
|
* @return A response stating success or failure of the user update
|
|
|
|
* @return A response stating success or failure of the user update
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
@PUT
|
|
|
|
@PUT
|
|
|
@ -305,10 +309,8 @@ public class UserHandler {
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* REST endpoint to delete a user account.
|
|
|
|
* REST endpoint to delete a user account.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @param info
|
|
|
|
* @param info passed from Jersey
|
|
|
|
* passed from Jersey
|
|
|
|
* @param id the unique id of the user which is being deleted
|
|
|
|
* @param id
|
|
|
|
|
|
|
|
* the unique id of the user which is being deleted
|
|
|
|
|
|
|
|
* @return A response stating success or failure of user deletion
|
|
|
|
* @return A response stating success or failure of user deletion
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
@DELETE
|
|
|
|
@DELETE
|
|
|
@ -335,10 +337,8 @@ public class UserHandler {
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Creates a <code>Response</code> related to an internal server error.
|
|
|
|
* Creates a <code>Response</code> related to an internal server error.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @param verbal
|
|
|
|
* @param verbal such as "creating", "deleting", "updating"
|
|
|
|
* such as "creating", "deleting", "updating"
|
|
|
|
* @param ex The exception, which is logged locally
|
|
|
|
* @param ex
|
|
|
|
|
|
|
|
* The exception, which is logged locally
|
|
|
|
|
|
|
|
* @return A response containing internal error with specific reasoning
|
|
|
|
* @return A response containing internal error with specific reasoning
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
private Response internalError(final String verbal, final Exception ex) {
|
|
|
|
private Response internalError(final String verbal, final Exception ex) {
|
|
|
@ -351,8 +351,7 @@ public class UserHandler {
|
|
|
|
* Creates a <code>Response</code> related to the user not providing a
|
|
|
|
* Creates a <code>Response</code> related to the user not providing a
|
|
|
|
* required field.
|
|
|
|
* required field.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @param fieldName
|
|
|
|
* @param fieldName the name of the field which is missing
|
|
|
|
* the name of the field which is missing
|
|
|
|
|
|
|
|
* @return A response explaining that the request is missing a field
|
|
|
|
* @return A response explaining that the request is missing a field
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
private Response missingRequiredField(final String fieldName) {
|
|
|
|
private Response missingRequiredField(final String fieldName) {
|
|
|
@ -367,10 +366,8 @@ public class UserHandler {
|
|
|
|
* Creates a <code>Response</code> related to the user providing a field
|
|
|
|
* Creates a <code>Response</code> related to the user providing a field
|
|
|
|
* that is too long.
|
|
|
|
* that is too long.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @param fieldName
|
|
|
|
* @param fieldName the name of the field that is too long
|
|
|
|
* the name of the field that is too long
|
|
|
|
* @param maxFieldLength the maximum length of <code>fieldName</code>
|
|
|
|
* @param maxFieldLength
|
|
|
|
|
|
|
|
* the maximum length of <code>fieldName</code>
|
|
|
|
|
|
|
|
* @return A response containing the bad field and the maximum field length
|
|
|
|
* @return A response containing the bad field and the maximum field length
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
private Response providedFieldTooLong(final String fieldName, final int maxFieldLength) {
|
|
|
|
private Response providedFieldTooLong(final String fieldName, final int maxFieldLength) {
|
|
|
@ -381,10 +378,8 @@ public class UserHandler {
|
|
|
|
* Creates the client-facing message related to the user providing a field
|
|
|
|
* Creates the client-facing message related to the user providing a field
|
|
|
|
* that is too long.
|
|
|
|
* that is too long.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @param fieldName
|
|
|
|
* @param fieldName the name of the field that is too long
|
|
|
|
* the name of the field that is too long
|
|
|
|
* @param maxFieldLength the maximum length of <code>fieldName</code>
|
|
|
|
* @param maxFieldLength
|
|
|
|
|
|
|
|
* the maximum length of <code>fieldName</code>
|
|
|
|
|
|
|
|
* @return a response containing the too long field and its length
|
|
|
|
* @return a response containing the too long field and its length
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
private static String getProvidedFieldTooLongMessage(final String fieldName, final int maxFieldLength) {
|
|
|
|
private static String getProvidedFieldTooLongMessage(final String fieldName, final int maxFieldLength) {
|
|
|
@ -397,8 +392,7 @@ public class UserHandler {
|
|
|
|
* Prepares a user account for output by redacting the appropriate fields.
|
|
|
|
* Prepares a user account for output by redacting the appropriate fields.
|
|
|
|
* This method side-effects the <code>user</code> parameter.
|
|
|
|
* This method side-effects the <code>user</code> parameter.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @param user
|
|
|
|
* @param user the user account which will have fields redacted
|
|
|
|
* the user account which will have fields redacted
|
|
|
|
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
private static void redactUserPasswordInfo(final User user) {
|
|
|
|
private static void redactUserPasswordInfo(final User user) {
|
|
|
|
user.setPassword(REDACTED_PASSWORD);
|
|
|
|
user.setPassword(REDACTED_PASSWORD);
|
|
|
@ -408,8 +402,7 @@ public class UserHandler {
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Validate the input field length.
|
|
|
|
* Validate the input field length.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @param inputField
|
|
|
|
* @param inputField the field to check
|
|
|
|
* the field to check
|
|
|
|
|
|
|
|
* @return true if input field bigger than the MAX_FIELD_LEN
|
|
|
|
* @return true if input field bigger than the MAX_FIELD_LEN
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
private boolean checkInputFieldLength(final String inputField) {
|
|
|
|
private boolean checkInputFieldLength(final String inputField) {
|
|
|
@ -418,10 +411,10 @@ public class UserHandler {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Revision history
|
|
|
|
* Revision history
|
|
|
|
*
|
|
|
|
* <p>
|
|
|
|
* -------------------------------------------------------------------------
|
|
|
|
* -------------------------------------------------------------------------
|
|
|
|
* Date Author Note
|
|
|
|
* Date Author Note
|
|
|
|
*
|
|
|
|
* <p>
|
|
|
|
* -------------------------------------------------------------------------
|
|
|
|
* -------------------------------------------------------------------------
|
|
|
|
* 2019/7/3 Dong Xiancun creat
|
|
|
|
* 2019/7/3 Dong Xiancun creat
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|