001/*******************************************************************************
002 * Copyright 2017 The MIT Internet Trust Consortium
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *   http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *******************************************************************************/
016package org.mitre.oauth2.service.impl;
017
018import java.io.UnsupportedEncodingException;
019import java.math.BigInteger;
020import java.security.SecureRandom;
021import java.util.Collection;
022import java.util.HashSet;
023
024import org.mitre.oauth2.model.ClientDetailsEntity;
025import org.mitre.oauth2.model.ClientDetailsEntity.AuthMethod;
026import org.mitre.oauth2.service.ClientDetailsEntityService;
027import org.mitre.openid.connect.config.ConfigurationPropertiesBean;
028import org.springframework.beans.factory.annotation.Autowired;
029import org.springframework.security.core.GrantedAuthority;
030import org.springframework.security.core.authority.SimpleGrantedAuthority;
031import org.springframework.security.core.userdetails.User;
032import org.springframework.security.core.userdetails.UserDetails;
033import org.springframework.security.core.userdetails.UserDetailsService;
034import org.springframework.security.core.userdetails.UsernameNotFoundException;
035import org.springframework.security.oauth2.common.exceptions.InvalidClientException;
036import org.springframework.stereotype.Service;
037import org.springframework.web.util.UriUtils;
038
039import com.google.common.base.Strings;
040
041/**
042 * Loads client details based on URI encoding as passed in from basic auth.
043 *
044 *  Should only get called if non-encoded provider fails.
045 *
046 * @author AANGANES
047 *
048 */
049@Service("uriEncodedClientUserDetailsService")
050public class UriEncodedClientUserDetailsService implements UserDetailsService {
051
052        private static GrantedAuthority ROLE_CLIENT = new SimpleGrantedAuthority("ROLE_CLIENT");
053
054        @Autowired
055        private ClientDetailsEntityService clientDetailsService;
056
057        @Autowired
058        private ConfigurationPropertiesBean config;
059
060        @Override
061        public UserDetails loadUserByUsername(String clientId) throws  UsernameNotFoundException {
062
063                try {
064                        String decodedClientId = UriUtils.decode(clientId, "UTF-8");
065
066                        ClientDetailsEntity client = clientDetailsService.loadClientByClientId(decodedClientId);
067
068                        if (client != null) {
069
070                                String encodedPassword = UriUtils.encodePathSegment(Strings.nullToEmpty(client.getClientSecret()), "UTF-8");
071
072                                if (config.isHeartMode() || // if we're running HEART mode turn off all client secrets
073                                                (client.getTokenEndpointAuthMethod() != null &&
074                                                        (client.getTokenEndpointAuthMethod().equals(AuthMethod.PRIVATE_KEY) ||
075                                                                client.getTokenEndpointAuthMethod().equals(AuthMethod.SECRET_JWT)))) {
076
077                                        // Issue a random password each time to prevent password auth from being used (or skipped)
078                                        // for private key or shared key clients, see #715
079
080                                        encodedPassword = new BigInteger(512, new SecureRandom()).toString(16);
081                                }
082
083                                boolean enabled = true;
084                                boolean accountNonExpired = true;
085                                boolean credentialsNonExpired = true;
086                                boolean accountNonLocked = true;
087                                Collection<GrantedAuthority> authorities = new HashSet<>(client.getAuthorities());
088                                authorities.add(ROLE_CLIENT);
089
090                                return new User(decodedClientId, encodedPassword, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
091                        } else {
092                                throw new UsernameNotFoundException("Client not found: " + clientId);
093                        }
094                } catch (UnsupportedEncodingException | InvalidClientException e) {
095                        throw new UsernameNotFoundException("Client not found: " + clientId);
096                }
097
098        }
099
100        public ClientDetailsEntityService getClientDetailsService() {
101                return clientDetailsService;
102        }
103
104        public void setClientDetailsService(ClientDetailsEntityService clientDetailsService) {
105                this.clientDetailsService = clientDetailsService;
106        }
107
108}