not included the authorities what I need in google oauth scope - youtube

hello I'm a novice in google api.
I already inserted youtube api authorities in this page https://console.cloud.google.com/apis/credentials/consent.
and then when I check google oauth page, it doesn't show any authorities what I need.
when I click any account, then just go to main page.
and I checked the issue in the intelliJ debug console.
here is only three authorities.
how can I solve this issue?
thank you in advance
here is the code below.
#Service
#RequiredArgsConstructor
public class CustomOAuth2UserService implements OAuth2UserService<OAuth2UserRequest, OAuth2User> {
private final UserRepository userRepository;
private final HttpSession httpSession;
#Override
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
OAuth2UserService<OAuth2UserRequest, OAuth2User> delegate = new DefaultOAuth2UserService();
OAuth2User oAuth2User = delegate.loadUser(userRequest);
String registrationId = userRequest.getClientRegistration().getRegistrationId();
String userNameAttributeName = userRequest.getClientRegistration()
.getProviderDetails()
.getUserInfoEndpoint()
.getUserNameAttributeName();
OAuthAttribute attributes = OAuthAttribute.of(registrationId, userNameAttributeName, oAuth2User.getAttributes());
User user = saveOrUpdate(attributes);
httpSession.setAttribute("user", new SessionUser(user));
return new DefaultOAuth2User(
Collections.singleton(new SimpleGrantedAuthority(user.getRoleKey())),
attributes.getAttributes(),
attributes.getNameAttributeKey());
}
private User saveOrUpdate(OAuthAttribute attribute) {
User user = userRepository.findByEmail(attribute.getEmail())
.map(it -> it.update(attribute.getName(), attribute.getPicture()))
.orElse(attribute.toEntity());
return userRepository.save(user);
}
}
#RequiredArgsConstructor
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final CustomOAuth2UserService customOAuth2UserService;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.headers().frameOptions().disable()
.and()
.authorizeRequests()
.antMatchers("/", "/css/**", "/images/**", "/js/**", "/h2-console/**").permitAll()
.antMatchers("/api/v1/**").hasRole(RoleType.USER.name())
.antMatchers("/welcome").permitAll()
.anyRequest().authenticated()
.and()
.logout()
.logoutSuccessUrl("/")
.and()
.oauth2Login()
.userInfoEndpoint()
.userService(customOAuth2UserService);
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.requestMatchers(PathRequest.toStaticResources().atCommonLocations());
}
}

Youtube Data api is channel based not not user based. You need to pick which channel you want to grant access the application access to. After that you will see the consent screen where it tells you what scopes of access the application is requesting.

Related

Checking username and password in Keycloak and roles in local database

I am trying to use keycloak for authentification by username and password. But at the same time I need to check, if the user from local database with the same name as user in keycloak has some roles in local database, PostgreSQL for example. The problem, I don't need keycloak roles, but need to check roles in local database.
Now my SecurityConfig which extends from KeycloakWebSecurityConfigurerAdapter looks like this:
#KeycloakConfiguration
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
#Autowired
RealmConfig realmConfig;
#Autowired
AuthConfig authConfig;
#Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new NullAuthenticatedSessionStrategy();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
SimpleAuthorityMapper grantedAuthorityMapper = new SimpleAuthorityMapper();
grantedAuthorityMapper.setPrefix("ROLE_");
KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
auth.authenticationProvider(keycloakAuthenticationProvider);
}
#Bean
public KeycloakConfigResolver keycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
//roles from local database
String roles = String.join(",", authConfig.roles());
http
.csrf().disable()
.authorizeRequests()
.antMatchers( "/api/gui*")
.hasAnyRole(roles)
.anyRequest()
.permitAll()
.and()
.exceptionHandling().accessDeniedHandler(accessDeniedHandler())
.and().logout().logoutUrl("/api/logout").logoutSuccessUrl("/api/").deleteCookies("OAuth_Token_Request_State", "JSESSIONID").invalidateHttpSession(true);
}
}
But hasAnyRoles check roles from keycloak users. Is there any way to make hasAnyRoles checking roles from local database user?

Which one is the correct OAuth2 flow

Tried to implement an OAuth2 in spring. But stuck as to which one would be the correct flow?
One flow I keep #Order(1) in (WebSecurityConfigurerAdapter)
Here on hitting the below I am presented with the default login page and I successfully login. http://localhost:8301/oauth/authorize?client_id=getidfromfacebook&response_type=code&redirect_uri=http://localhost:9191/xyz
Redirected to the authorize page and after acceptance get a code http://localhost:9191/xyz?code=mkuyG4 which helps in getting the access and refresh token by curl http://localhost:8301/oauth/token -H"Content-type: application/x-www-form-urlencoded" -d'grant_type=authorization_code&redirect_uri=http://localhost:9191/xyz&code=LJQef7' -u getidfromfacebook:getit
I am also able to get a fresh access token from the given refresh token via curl --location --request POST 'http://localhost:8301/oauth/token?grant_type=refresh_token&client_id=getidfromfacebook&refresh_token=a045acd6-5d66-4db5-a509-4bdadca065e0' -u getidfromfacebook:getit
The problem I face here is that with the given access token, I am not able to access any of the resources mentioned in
antMatchers("/api/**").authenticated() (ResourceServerConfigurerAdapter).
Like in postman provided a Header with Authorization and value Bearer access-token or like curl -H"Authorization: Bearer 1738520f-9f9c-43ef-8f7f-f5886075a7aa" http://localhost:8301/api/users/all/.
Note, I am able to get access-tokens for other grant_types as well and also refresh it. But no access to resources via the token. Point to note is if I hit the resource url, I am presented with the default login and able to access it.
The other flow I remove #Order(1). When I try to go through the authorization code flow, the system complains about user needs to be logged in for a request of (auth)code. So not able to proceed as am not presented with the default login page.
However, I am able to proceed with the password grant type curl http://localhost:8301/oauth/token -d"grant_type=password&username=username&password=userpassword" -H"Content-type:application/x-www-form-urlencoded; charset=utf-8" -u getidfromfacebook:getit
I am also able to access the resources via the access token.
Which one is the correct approach?
Why am I not able to access the resources in former approach.
#Configuration
#EnableAuthorizationServer
#AllArgsConstructor
public class AuthorizationServerConfigAdapter extends AuthorizationServerConfigurerAdapter {
private final AuthenticationManager authenticationManager;
private final ClientService clientService;
private final UserService userService;
#Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security
.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(clientService);
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.authenticationManager(this.authenticationManager)
.userDetailsService(userService)
;
}
/*****************************/
#Configuration
#EnableResourceServer
public class ResourceServerConfigAdapter extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/api/**").authenticated()
.antMatchers("/").permitAll();
}
}
/*****************************/
#Configuration
#EnableWebSecurity
#AllArgsConstructor
#Order(1) // Since we have this working as N, Z and R sever.
public class WebSecurityConfigAdapter extends WebSecurityConfigurerAdapter {
private final UserService userService;
#Override
protected void configure(HttpSecurity http) throws Exception {
//http.csrf().disable();
http
.antMatcher("/**")
.authorizeRequests()
.antMatchers("/oauth/authorize**", "/login**", "/error**")
.permitAll()
.and()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin().permitAll();
}
#Override
protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder
.userDetailsService(userService)
.passwordEncoder(passwordEncoder());
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(BCryptPasswordEncoder.BCryptVersion.$2A);
}
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.requestMatcher(request -> {
String auth = request.getHeader("Authorization");
return (auth != null && auth.startsWith("Bearer"));
})
.authorizeRequests()
.antMatchers("/api/**").authenticated()
.antMatchers("/").permitAll();
}

JWT : why do I get a new token after clearing localstorage?

I have an Angular 7 app with a spring API. I use spring security, JWT tokens, and https://github.com/manfredsteyer/angular-oauth2-oidc to handle login.
I'm able to login, but when I logout and clic on login once again, I immediately get a new token, without having to connect.
I'm new to spring security and JWT tokens, but from what I know, I cannot properly logout from the back, the classic way is to remove token from the front. That's what the library do, and to be sure I tried by emptying manualy the localStorage (where token is stored), but even with localStorage cleared, when I try to login, I get a new token immediately.
Any idea about what happengin and how can I logout?
Authorization server config :
#Configuration
#EnableAuthorizationServer
public class OAuth2AuthorizationServerConfigJwt extends AuthorizationServerConfigurerAdapter {
#Override
public void configure(final ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory().withClient("sampleClientId")
.authorizedGrantTypes("implicit")
.scopes("read", "write", "foo", "bar")
.autoApprove(true)/*.accessTokenValiditySeconds(3600)*/
.redirectUris("http://localhost:4200");
}
#Override
public void configure(final AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
final TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
tokenEnhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer(), accessTokenConverter()));
endpoints.tokenStore(tokenStore()).tokenEnhancer(tokenEnhancerChain);
}
#Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
#Bean
public JwtAccessTokenConverter accessTokenConverter() {
final JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("123");
return converter;
}
#Bean
public TokenEnhancer tokenEnhancer() {
return new CustomTokenEnhancer();
}
}
Edit :
It seems that this was due to the lack of
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
But now that I've added it, I'm stuck on the login form, seems that there's still something missing. Here my config :
#Override
protected void configure(final HttpSecurity http) throws Exception {
http.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/login").permitAll()
.antMatchers("/user").permitAll()
.antMatchers("/registrationConfirm").permitAll()
.antMatchers("/user/confirm/**").permitAll()
.antMatchers("/user/registration/**").permitAll()
.antMatchers("/oauth/token/revokeById/**").permitAll()
.antMatchers("/tokens/**").permitAll()
.anyRequest().authenticated()
.and().formLogin().permitAll();
}

Single Sign On with Spring Security OAuth2 and JWT

I am trying to implement Single Sign On with Spring Security OAuth2 and JWT.
I use two separate applications:
An Authorization Server – which is the central authentication mechanism
Client Application: the applications using SSO
When a user tries to access a secured page in the client app, they’ll be redirected to authenticate first, via the Authentication Server.
And I am using the Authorization Code grant type out of OAuth2 to drive the delegation of authentication.
Authorization server:
#Configuration
#EnableAuthorizationServer
public class OAuth2AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
public static final Logger LOGGER = LoggerFactory.getLogger(AuthorizationServerConfigurerAdapter.class);
#Autowired
private AuthenticationManager authenticationManager;
#Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
#Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("abcd");
return converter;
}
#Bean
#Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
defaultTokenServices.setSupportRefreshToken(true);
defaultTokenServices.setTokenEnhancer(accessTokenConverter());
return defaultTokenServices;
}
#Override
public void configure(ClientDetailsServiceConfigurer clientDetailsServiceConfigurer) throws Exception {
clientDetailsServiceConfigurer
.inMemory()
.withClient("webapp")
.secret("Pass")
.authorizedGrantTypes("implicit", "refresh_token", "password", "authorization_code")
.scopes("user_info")
.autoApprove(true);
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.authenticationManager(authenticationManager);
}
}
Security Configuration on Authorization Server
#Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Value("${ldap.url}")
private String ldapUrl;
#Value("${ldap.userDnPatterns}")
private String ldapUserDnPatterns;
#Autowired
private PersonService personService;
#Autowired
private RoleService roleService;
#Override
protected void configure(HttpSecurity http) throws Exception { // #formatter:off
http.requestMatchers()
.antMatchers("/login", "/oauth/authorize")
.and()
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.formLogin()
.permitAll();
} // #formatter:on
#Bean(name = "authenticationManager")
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.authenticationProvider(this.ldapAndDatabaseAuthenticationProvider());
}
#Bean(name="ldapAuthenticationProvider")
public AuthenticationProvider ldapAndDatabaseAuthenticationProvider(){
LdapUserDetailsMapper userDetailsMapper = new LdapUserDetailsMapper();
userDetailsMapper.setRoleAttributes(new String[]{"groupMembership"});
LdapAndDatabaseAuthenticationProvider provider =
new LdapAndDatabaseAuthenticationProvider(
this.ldapAuthenticator(),
this.ldapAuthoritiesPopulator(),
this.personService);
provider.setUserDetailsContextMapper(userDetailsMapper);
return provider;
}
#Bean( name = "ldapAuthoritiesPopulator" )
public LdapAndDatabaseAuthoritiesPopulator ldapAuthoritiesPopulator(){
return new LdapAndDatabaseAuthoritiesPopulator(this.contextSource(), "", roleService);
}
#Bean( name = "ldapAuthenticator" )
public LdapAuthenticator ldapAuthenticator() {
BindAuthenticator authenticator = new BindAuthenticator( this.contextSource() );
authenticator.setUserDnPatterns(new String[]{"cn={0},ou=prod,o=TEMP"});
return authenticator;
}
#Bean( name = "contextSource" )
public DefaultSpringSecurityContextSource contextSource() {
DefaultSpringSecurityContextSource contextSource =
new DefaultSpringSecurityContextSource( ldapUrl );
return contextSource;
}
}
application.properties:
server.port=8888
server.context-path=/auth
security.basic.enabled=false
When I login the client application, It correctly forwards to Authorization Server for Single Sign On.
I enter the user credentials. User successfully get authenticated, but then I see the below error on browser:
OAuth Error
error="invalid_grant", error_description="A redirect_uri can only be
used by implicit or authorization_code grant types."
URL Shows:
http://localhost:8888/auth/oauth/authorize?client_id=webapp&redirect_uri=http://localhost:8080/jwt/webapp&response_type=code&state=LGvAzj
I also see the below at the log:
02:14:43.610 [http-nio-8888-exec-6] DEBUG o.s.s.o.p.e.FrameworkEndpointHandlerMapping/getHandlerInternal Looking up handler method for path /oauth/authorize
02:14:43.614 [http-nio-8888-exec-6] DEBUG o.s.s.o.p.e.FrameworkEndpointHandlerMapping/getHandlerInternal Returning handler method [public org.springframework.web.servlet.ModelAndView org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint.authorize(java.util.Map<java.lang.String, java.lang.Object>,java.util.Map<java.lang.String, java.lang.Str ing>,org.springframework.web.bind.support.SessionStatus,java.security.Principal)]
02:14:43.849 [http-nio-8888-exec-6] INFO o.s.s.o.p.e.AuthorizationEndpoint/handleOAuth2Exception Handling OAuth2 error: error="invalid_grant", error_description="A redirect_uri can only be used by implicit or authorization_code grant types."
Can you please help me to find the problem?
UPDATE
Actually, Dur is right. This configuration is correct and works fine. I had another configuration file which configures JdbcClientDetails and it was overwriting the clientDetailsService created with inmemory in this configuration.

spring-boot Actuator together with Spring Security and Form Basic Auth

I have added "spring-boot-starter-actuator" dependency to my spring-boot project.
The project already has form based security.
The root context for the application is "/".
I have added the actuator at the context root "/actuators" by adding to application.yaml:
management:
context-path: /actuators
The non-sensitive actuators are working, such as "health".
When I try to access the sensitive actuators, the popup appears for username/password. The authentication takes place, but then I see "403" Access is Denied.
Here is the configuration for Web security:
#Configuration
#EnableWebSecurity
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private AuthenticationLookupService authenticationLookupService;
private AuthenticationManagerBuilder authenticationManagerBuilder;
private UrlSuccessAuthenticationHandler successHandler;
#Autowired
public void setAuthenticationLookupService(AuthenticationLookupService authenticationLookupService) {
this.authenticationLookupService = authenticationLookupService;
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
this.authenticationManagerBuilder = auth;
}
#Autowired
public void setSuccessHandler(UrlSuccessAuthenticationHandler successHandler) {
this.successHandler = successHandler;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/", "/index.html", "/auth/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/index.html").successHandler(successHandler)
.permitAll()
.and()
.logout()
.permitAll();
http.csrf().disable(); // todo: fix later
}
#PostConstruct
public void process() throws Exception {
this.authenticationManagerBuilder.userDetailsService(this.authenticationLookupService).passwordEncoder(new ShaPasswordEncoder());
}
}
Add below values in application.properties or application.yml and then when popup asks for username and password provide this credentials
security.user.name=admin
security.user.password=secret
If you are providing your values check if that user has ADMIN role, because actuator needs ADMIN role user to access sensitive end points.
Update
If you are using spring-boot 1.5.*+ then user should have ACTUATOR role

Resources