Compare commits

...

2 Commits

Author SHA1 Message Date
25b0b34b8d SpringBoot: ApiUser ShortHashService
implemented in form of CutomUserDetails, which is injected into endpint
if user was sucessfully authorized
2023-08-25 23:45:14 +02:00
ae72015cdd Corda: new network layout 2023-08-24 12:02:29 +02:00
7 changed files with 208 additions and 26 deletions

View File

@ -1,10 +1,10 @@
package djmil.cordacheckers; package djmil.cordacheckers;
import java.security.Principal;
import java.util.List; import java.util.List;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@ -32,9 +32,9 @@ public class ApiController {
* @return a Json list of active games * @return a Json list of active games
*/ */
@GetMapping("/api/activegames") @GetMapping("/api/activegames")
public ResponseEntity<String> dashboard(Principal principal) { public ResponseEntity<String> dashboard(@AuthenticationPrincipal ApiUserDetails user) {
return ResponseEntity.ok("{ \"ActiveGames\" : [\"game\", \"GAME\", \""+principal.getName()+ "\" ] }" ); return ResponseEntity.ok("{ \"ActiveGames\" : [\"game\", \"GAME\", \""+user.getShortHash()+ "\" ] }" );
} }
} }

View File

@ -0,0 +1,19 @@
package djmil.cordacheckers;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
public class ApiUserDetails extends User {
private final String shortHash;
public ApiUserDetails(UserDetails user, String shortHash) {
super(user.getUsername(), user.getPassword(), user.isEnabled(), user.isAccountNonExpired(), user.isCredentialsNonExpired(), user.isAccountNonLocked(), user.getAuthorities());
this.shortHash = shortHash;
}
public String getShortHash() {
return this.shortHash;
}
}

View File

@ -0,0 +1,45 @@
package djmil.cordacheckers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
@Service
public class ApiUserDetailsService implements UserDetailsService {
@Autowired
@Lazy
private PasswordEncoder encoder;
@Autowired
@Lazy
ApiUserShortHashService apiUserShortHash;
@Override
public ApiUserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// Load user from database
// User user = userRepository.findByUsername(username);
// if (user == null) {
// throw new UsernameNotFoundException("User not found");
// }
System.out.println("Load user "+username);
User.UserBuilder users = User.builder();
UserDetails alice = users
.username(username)
.password(encoder.encode("qaz123"))
.build();
ApiUserDetails apiUser = new ApiUserDetails(alice, apiUserShortHash.getShortHashBy(username));
return apiUser;
}
}

View File

@ -0,0 +1,51 @@
package djmil.cordacheckers;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.naming.InvalidNameException;
import org.springframework.stereotype.Service;
import djmil.cordacheckers.cordaclient.CordaClient;
import djmil.cordacheckers.cordaclient.pojo.virtualNodes;
@Service
public class ApiUserShortHashService {
static final Locale locale = Locale.getDefault();
Map<String, String> apiUserShortHashMap;
ApiUserShortHashService(CordaClient client) {
this.apiUserShortHashMap = setApiUserShortHashMap(client);
}
private static Map<String, String> setApiUserShortHashMap(CordaClient client) {
Map<String, String> map = new HashMap<>();
List<virtualNodes> vNodesList = client.getVirtualnode();
try {
for (virtualNodes vNode : vNodesList) {
var identity = vNode.holdingIdentity();
if (identity.isPlayer()) {
map.put(identity.getName().toLowerCase(locale), identity.shortHash());
}
}
} catch (InvalidNameException e) {
// TODO: logs
System.out.println("Unable to get ShorHash map for vNode: "+e.getExplanation());
e.printStackTrace();
}
System.out.println("ApiUserShortHashMap " + map);
return map;
}
String getShortHashBy(String apiUserName) {
return this.apiUserShortHashMap.get(apiUserName.toLowerCase(locale));
}
}

View File

@ -0,0 +1,46 @@
package djmil.cordacheckers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
@Service
public class CustomAuthenticationProvider implements AuthenticationProvider {
@Autowired
@Lazy
private PasswordEncoder encoder;
@Autowired
private ApiUserDetailsService userDetailsService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = authentication.getName();
String password = authentication.getCredentials().toString();
ApiUserDetails user = userDetailsService.loadUserByUsername(username);
return checkPassword(user, password);
}
@Override
public boolean supports(Class<?> aClass) {
return UsernamePasswordAuthenticationToken.class.isAssignableFrom(aClass);
}
private Authentication checkPassword(ApiUserDetails user, String rawPassword) {
if (encoder.matches(rawPassword, user.getPassword())) {
return new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities());
} else {
throw new BadCredentialsException("Bad credentials");
}
}
}

View File

@ -1,38 +1,59 @@
package djmil.cordacheckers; package djmil.cordacheckers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.core.userdetails.User; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager; import org.springframework.security.web.SecurityFilterChain;
import static org.springframework.security.config.Customizer.withDefaults;
@Configuration @Configuration
@EnableWebSecurity
public class SecurityConfig { public class SecurityConfig {
@Bean @Bean
PasswordEncoder passwordEncoder() { PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(); return PasswordEncoderFactories.createDelegatingPasswordEncoder();
} }
@Bean @Autowired
UserDetailsService hardcodedCordaUsers(PasswordEncoder passwordEncoder) { CustomAuthenticationProvider authenticationProvider;
User.UserBuilder users = User.builder();
UserDetails alice = users @Autowired
.username("alice") public void configure(AuthenticationManagerBuilder auth) throws Exception {
.password(passwordEncoder.encode("qaz123")) auth.authenticationProvider(authenticationProvider);
.build();
UserDetails bob = users
.username("bob")
.password(passwordEncoder.encode("qaz123"))
.build();
return new InMemoryUserDetailsManager(alice, bob);
} }
// @Bean
// SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
// http
// .authorizeRequests(authorizeRequests ->
// authorizeRequests.anyRequest().authenticated());
// .formLogin(withDefaults());
// return http.build();
// }
// @Bean
// UserDetailsService hardcodedCordaUsers(PasswordEncoder passwordEncoder) {
// User.UserBuilder users = User.builder();
// UserDetails alice = users
// .username("alice")
// .password(passwordEncoder.encode("qaz123"))
// .build();
// UserDetails bob = users
// .username("bob")
// .password(passwordEncoder.encode("qaz123"))
// .build();
// return new InMemoryUserDetailsManager(alice, bob);
// }
} }

View File

@ -1,18 +1,18 @@
[ [
{ {
"x500Name" : "CN=Alice, OU=Test Dept, O=R3, L=London, C=GB", "x500Name" : "CN=Alice, OU=Player, O=Checkers, L=Zug, C=CH",
"cpi" : "MyCorDapp" "cpi" : "MyCorDapp"
}, },
{ {
"x500Name" : "CN=Bob, OU=Test Dept, O=R3, L=London, C=GB", "x500Name" : "CN=Bob, OU=Player, O=Checkers, L=Kviv, C=UA",
"cpi" : "MyCorDapp" "cpi" : "MyCorDapp"
}, },
{ {
"x500Name" : "CN=Charlie, OU=Test Dept, O=R3, L=London, C=GB", "x500Name" : "CN=Charlie, OU=Player, O=Checkers, L=London, C=GB",
"cpi" : "MyCorDapp" "cpi" : "MyCorDapp"
}, },
{ {
"x500Name" : "CN=Dave, OU=Test Dept, O=R3, L=London, C=GB", "x500Name" : "CN=Kumar, OU=Player, O=Checkers, L=Mumbai, C=IN",
"cpi" : "MyCorDapp" "cpi" : "MyCorDapp"
}, },
{ {