Enable multiple roles per user (backend)
[controller.git] / opendaylight / usermanager / src / main / java / org / opendaylight / controller / usermanager / internal / UserConfig.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.controller.usermanager.internal;
10
11 import java.io.Serializable;
12 import java.util.ArrayList;
13 import java.util.Iterator;
14 import java.util.List;
15 import java.util.regex.Matcher;
16 import java.util.regex.Pattern;
17
18 import org.apache.commons.lang3.builder.EqualsBuilder;
19 import org.apache.commons.lang3.builder.HashCodeBuilder;
20 import org.opendaylight.controller.sal.authorization.AuthResultEnum;
21 import org.opendaylight.controller.sal.utils.Status;
22 import org.opendaylight.controller.sal.utils.StatusCode;
23 import org.opendaylight.controller.usermanager.AuthResponse;
24
25 /**
26  * Configuration Java Object which represents a Local AAA user configuration
27  * information for User Manager.
28  */
29 public class UserConfig implements Serializable {
30     private static final long serialVersionUID = 1L;
31
32     /*
33      * Clear text password as we are moving to some MD5 digest for when saving
34      * configurations
35      */
36     protected String user;
37     protected List<String> roles;
38     private String password;
39     private static final int USERNAME_MAXLENGTH = 32;
40     private static final int PASSWORD_MINLENGTH = 5;
41     private static final int PASSWORD_MAXLENGTH = 256;
42     private static final Pattern INVALID_USERNAME_CHARACTERS = Pattern
43             .compile("([/\\s\\.\\?#%;\\\\]+)");
44
45     public UserConfig() {
46     }
47
48     public UserConfig(String user, String password, List<String> roles) {
49         this.user = user;
50         this.password = password;
51         this.roles = (roles == null) ? new ArrayList<String>()
52                 : new ArrayList<String>(roles);
53     }
54     
55     public String getUser() {
56         return user;
57     }
58
59     public String getPassword() {
60         return password;
61     }
62
63     public List<String> getRoles() {
64         return new ArrayList<String>(roles);
65     }
66
67     @Override
68     public int hashCode() {
69         return HashCodeBuilder.reflectionHashCode(this);
70     }
71
72     @Override
73     public boolean equals(Object obj) {
74         return EqualsBuilder.reflectionEquals(this, obj);
75     }
76
77     @Override
78     public String toString() {
79         return "UserConfig[user=" + user + ", password=" + password + ", roles=" + roles +"]";
80     }
81
82     public Status validate() {
83         Status validCheck = validateRoles();
84         if (validCheck.isSuccess()) {
85             validCheck = validateUsername();
86         }
87         if (validCheck.isSuccess()) {
88             validCheck = validatePassword();
89         }
90         return validCheck;
91     }
92
93     protected Status validateUsername() {
94         if (user == null || user.isEmpty()) {
95             return new Status(StatusCode.BADREQUEST, "Username cannot be empty");
96         }
97
98         Matcher mUser = UserConfig.INVALID_USERNAME_CHARACTERS.matcher(user);
99         if (user.length() > UserConfig.USERNAME_MAXLENGTH
100                 || mUser.find() == true) {
101             return new Status(StatusCode.BADREQUEST,
102                     "Username can have 1-32 non-whitespace "
103                             + "alphanumeric characters and any special "
104                             + "characters except ./#%;?\\");
105         }
106
107         return new Status(StatusCode.SUCCESS);
108     }
109
110     private Status validatePassword() {
111         if (password == null || password.isEmpty()) {
112             return new Status(StatusCode.BADREQUEST, "Password cannot be empty");
113         }
114
115         if (password.length() < UserConfig.PASSWORD_MINLENGTH
116                 || password.length() > UserConfig.PASSWORD_MAXLENGTH) {
117             return new Status(StatusCode.BADREQUEST,
118                     "Password should have 5-256 characters");
119         }
120         return new Status(StatusCode.SUCCESS);
121     }
122
123     protected Status validateRoles() {
124         if (roles == null || roles.isEmpty()) {
125             return new Status(StatusCode.BADREQUEST, "No role specified");
126         }
127         return new Status(StatusCode.SUCCESS);
128     }
129
130     public Status update(String currentPassword, String newPassword,
131             List<String> newRoles) {
132         // To make any changes to a user configured profile, current password
133         // must always be provided
134         if (!this.password.equals(currentPassword)) {
135             return new Status(StatusCode.BADREQUEST,
136                     "Current password is incorrect");
137         }
138         
139         // Create a new object with the proposed modifications
140         UserConfig proposed = new UserConfig();
141         proposed.user = this.user;
142         proposed.password = (newPassword != null)? newPassword : this.password;
143         proposed.roles = (newRoles != null)? newRoles : this.roles;
144         
145         // Validate it
146         Status status = proposed.validate();
147         if (!status.isSuccess()) {
148             return status;
149         }
150         
151         // Accept the modifications
152         this.user = proposed.user;
153         this.password = proposed.password;
154         this.roles = new ArrayList<String>(proposed.roles);
155         
156         return status;
157     }
158
159     public AuthResponse authenticate(String clearTextPass) {
160         AuthResponse locResponse = new AuthResponse();
161         if (password.equals(clearTextPass)) {
162             locResponse.setStatus(AuthResultEnum.AUTH_ACCEPT_LOC);
163             locResponse.addData(getRolesString());
164         } else {
165             locResponse.setStatus(AuthResultEnum.AUTH_REJECT_LOC);
166         }
167         return locResponse;
168     }
169     
170     protected String getRolesString() {
171         StringBuffer buffer = new StringBuffer();
172         if (!roles.isEmpty()) {
173             Iterator<String> iter = roles.iterator();
174             buffer.append(iter.next());
175             while (iter.hasNext()) {
176                 buffer.append(" ");
177                 buffer.append(iter.next());
178             }
179         }
180         return buffer.toString();
181     }
182 }