001package com.nimbusds.oauth2.sdk;
002
003
004import java.util.LinkedHashMap;
005import java.util.Map;
006
007import net.jcip.annotations.Immutable;
008
009import com.nimbusds.oauth2.sdk.auth.Secret;
010
011
012/**
013 * Resource owner password credentials grant. Used in access token requests
014 * with the resource owner's username and password. This class is immutable.
015 *
016 * <p>Related specifications:
017 *
018 * <ul>
019 *     <li>OAuth 2.0 (RFC 6749), section 4.3.2.
020 * </ul>
021 *
022 * @author Vladimir Dzhuvinov
023 */
024@Immutable
025public class ResourceOwnerPasswordCredentialsGrant extends AuthorizationGrant {
026
027
028        /**
029         * The associated grant type.
030         */
031        public static final GrantType GRANT_TYPE = GrantType.PASSWORD;
032
033
034        /**
035         * The username.
036         */
037        private final String username;
038
039
040        /**
041         * The password.
042         */
043        private final Secret password;
044
045
046        /**
047         * The requested scope.
048         */
049        private final Scope scope;
050
051
052        /**
053         * Creates a new resource owner password credentials grant.
054         *
055         * @param username The resource owner's username. Must not be
056         *                 {@code null}.
057         * @param password The resource owner's password. Must not be
058         *                 {@code null}.
059         * @param scope    The requested scope, {@code null} if not
060         *                 specified.
061         */
062        public ResourceOwnerPasswordCredentialsGrant(final String username,
063                                                     final Secret password,
064                                                     final Scope scope) {
065
066                super(GRANT_TYPE);
067
068                if (username == null)
069                        throw new IllegalArgumentException("The username must not be null");
070
071                this.username = username;
072
073                if (password == null)
074                        throw new IllegalArgumentException("The password must not be null");
075
076                this.password = password;
077
078                this.scope = scope;
079        }
080
081
082        /**
083         * Gets the resource owner's username.
084         *
085         * @return The username.
086         */
087        public String getUsername() {
088
089                return username;
090        }
091
092
093        /**
094         * Gets the resource owner's password.
095         *
096         * @return The password.
097         */
098        public Secret getPassword() {
099
100                return password;
101        }
102
103
104        /**
105         * Gets the requested scope.
106         *
107         * @return The requested scope.
108         */
109        public Scope getScope() {
110
111                return scope;
112        }
113
114
115        @Override
116        public Map<String,String> toParameters() {
117
118                Map<String,String> params = new LinkedHashMap<String,String>();
119
120                params.put("grant_type", GRANT_TYPE.getValue());
121
122                params.put("username", username);
123                params.put("password", password.getValue());
124
125                if (scope != null)
126                        params.put("scope", scope.toString());
127
128                return params;
129        }
130
131
132        /**
133         * Parses a resource owner password credentials grant from the
134         * specified parameters.
135         *
136         * <p>Example:
137         *
138         * <pre>
139         * grant_type=password
140         * username=johndoe
141         * password=A3ddj3w
142         * </pre>
143         *
144         * @param params The parameters.
145         *
146         * @return The resource owner password credentials grant.
147         *
148         * @throws ParseException If parsing failed.
149         */
150        public static ResourceOwnerPasswordCredentialsGrant parse(final Map<String,String> params)
151                throws ParseException {
152
153                // Parse grant type
154                String grantTypeString = params.get("grant_type");
155
156                if (grantTypeString == null)
157                        throw new ParseException("Missing \"grant_type\" parameter", OAuth2Error.INVALID_REQUEST);
158
159                GrantType grantType = new GrantType(grantTypeString);
160
161                if (! grantType.equals(GRANT_TYPE))
162                        throw new ParseException("The \"grant_type\" must be " + GRANT_TYPE, OAuth2Error.INVALID_GRANT);
163
164                // Parse the username
165                String username = params.get("username");
166
167                if (username == null || username.trim().isEmpty())
168                        throw new ParseException("Missing or empty \"username\" parameter", OAuth2Error.INVALID_REQUEST);
169
170                // Parse the password
171                String passwordString = params.get("password");
172
173                if (passwordString == null || passwordString.trim().isEmpty())
174                        throw new ParseException("Missing or empty \"password\" parameter", OAuth2Error.INVALID_REQUEST);
175
176                Secret password = new Secret(passwordString);
177
178                // Parse optional scope
179                String scopeValue = params.get("scope");
180
181                Scope scope = null;
182
183                if (scopeValue != null)
184                        scope = Scope.parse(scopeValue);
185
186                return new ResourceOwnerPasswordCredentialsGrant(username, password, scope);
187        }
188}