I'm working on an application with Spring Boot 5 and OIDC. I've configured OIDC with Google and it works fine. I'm redirected to login at Google and then it redirects me to the app creating a new session. Now I'm trying to use Google One-Tap. It works fine as well. When user clicks on the one-tap's modal to continue with his Google identity I receive a POST with the id_token. What I want to do is to create a Spring session from this POST as it is created when user is logged by OIDC.
I think the right way is to create a Filter extending AbstractAuthenticationProcessingFilter. I've found some references here and here but I don't have the access_token when receiving the one-tap POST:
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
...
OAuth2AuthenticationToken oauth2Authentication = new OAuth2AuthenticationToken(
authenticationResult.getPrincipal(),
authenticationResult.getAuthorities(),
authenticationResult.getClientRegistration().getRegistrationId());
oauth2Authentication.setDetails(authenticationDetails);
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(
authenticationResult.getClientRegistration(),
oauth2Authentication.getName(),
authenticationResult.getAccessToken(),
authenticationResult.getRefreshToken());
this.authorizedClientRepository.saveAuthorizedClient(authorizedClient, oauth2Authentication, request, response);
return oauth2Authentication;
}
Has anyone tried to do it before ?
I've finally found a solution. I've shared the code here. Hope it helps to anyone dealing with the same issue.
Related
Well, I'm consuming SAML SSO created by enterprise where I work. Once user and password is typed SAML service redirects to given url as POST request, e.g.
https://some-saml-url.domine.com/idp/startSSO.ping
then fill up user and password fields and redirects to my app authentication url as POST with form data encrypted as SAMLResponse.
I'm using spring boot 2.4.5. Here my controller
#Controller
#CrossOrigin("*")
public class AuthenticationController {
#PostMapping(value = "/auth", consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE})
public String authentication(HttpServletRequest request, HttpServletResponse response) throws GasStationException {
//do something to retrieve SAMLResponse
return "redirect:/";
}
}
I'm able to catch request inside controller but not to get form data. I've tried multiple solutions I've found through internet but nothing. Hope somebody have an idea or solution that helps me.
Ok, if somebody have this kind of issue and is using logbook, well that's why. In logback file I have this one
<logger name="org.zalando.logbook" level="TRACE" />
And don't know why logbook takes form data values print them in console and delete them from request. After comment this line all works.
I have a web app that I am migrating to Grails 3.3.9 (from Grails 2.3.11). The current version of the application utilizes Spring Security LDAP for authentication (user sees login form when they try to access site and they type in username and password). The newer version of the application will utilize the Spring Security SAML plugin for authentication (commonly referred to as Single Sign On).
I have the Single Sign On (SSO) working however the SSO Login Page is only accessible when a user is at our office (has a certain IP address). In the cases where the user is not at our office (has an IP address not in our network). I would like the user to have the option to login with the Spring Security LDAP login form.
I'm sort of lost how to do it though. From the info I've gathered I need to define my security provider in application.groovy(I've used the default Spring Security providers as they seem to do the job individually). What I don't understand though is how do I tell Grails which of the two login methods to use per user. In my instance it would be checking the IP address of the user (which I already have the code for), but how do I then say, for example:
if(ipAddress matches internalIPRange) use samlAuthenticationProvider
else{use ldapAuthProvider}
Here is the provider set up in application.groovy
grails.plugin.springsecurity.providerNames = ['samlAuthenticationProvider', 'ldapAuthProvider', 'daoAuthenticationProvider', 'anonymousAuthenticationProvider']
Also I don't know how to actually call the provider manually (something like provider.invoke() if I had to guess).
It appears to be fairly easy to implement.
You extend the ExceptionTranslationFilter like so:
class IpAwareExceptionTranslationFilter extends ExceptionTranslationFilter {
AuthenticationEntryPoint ldapAuthenticationEntryPoint
#Override
void sendStartAuthentication(HttpServletRequest request,
HttpServletResponse response, FilterChain chain,
AuthenticationException reason) throws ServletException, IOException {
SecurityContextHolder.context.authentication = null
requestCache.saveRequest request, response
logger.debug 'Calling Authentication entry point.'
if( isAllowedIpAddress( request ) )
authenticationEntryPoint.commence request, response, reason // default SAML
else
ldapAuthenticationEntryPoint.commence request, response, reason // LDAP
}
}
Then you declare your filter as a bean in resources.groovy:
beans = {
exceptionTranslationFilter( IpAwareExceptionTranslationFilter ){
authenticationEntryPoint = new LoginUrlAuthenticationEntryPoint( '/saml/login' )
ldapAuthenticationEntryPoint = new LoginUrlAuthenticationEntryPoint( '/ldap/login' )
}
}
and it should replace the default exceptionTranslationFilter in the filter chain.
I'm trying to build an api with Google Cloud Endpoints.
As Cloud Endpoints does not provide authentication beside Googles own OAuth I try to build my own. Therefore I want to access the parameters provided for the API (for example #Named("token") token) inside a servlet filter.
Unfortunately I cannot find any of the provided information inside the httpRequest. Is that normal? Is there a possibility to access the parameters?
I would appreciate if someone could help me!
UPDATE:
With the infos from jirungaray I tried to build an authentication using headers but ran into the same problem. Used a REST-Client to send some headers as I could not figure out how to do this with the API Explorer. Inside my filter I try to access the token from the headers:
#Override
public void doFilter(
ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String authToken = httpRequest.getHeader(Constants.AUTH_TOKEN);
...
chain.doFilter(request, response);
}
The reason why I try to do something like this, is that I'm using Guice for Dependency Injection and want my token to be injected inside another object.
With Guice I have the following Provider using the token to inject a FacebookClient (using the token) per request.
#Provides
public FacebookClient getFacebookClientProvider(#Named("fbToken") Provider<String> fbToken) {
return new DefaultFacebookClient(fbToken.get(), Version.VERSION_2_2);
}
As described in the Guice wiki (SevletModule) this uses a sevlet filter to get the information from the request.
Is there any solution to achieve this kind of DI with Cloud Endpoints?
Philip,
Yes, it does makes sense you are getting an empty request. Your endpoint calls are first handled by Google (they receive the API calls) and then those are processed and sent to a handler in your app. As this is all done in the background it's very easy to miss that your endpoints aren't actually getting the same request you sent, they get a completely different request sent from Google's infrastructure.
Even though your approach should work including tokens info in url makes them easier to sniff, even if you use SSL or encrypt your params the token is there in plain sight.
For what you are trying to achieve I recommend you include the token as a header in your request and retrieve that header by accessing the HTTPRequest directly on the endpoint, this is injected automatically if you include an HTTPServletRequest param in you endpoint method.
eg.
public APIResponse doSomething(SomeComplexRquestModel request,
HttpServletRequest rawRequest) {
}
If you still feel you should go with your original approach just comment and I'll help you debug the issue.
Spring social and security experts,
I have the following use case:
User requests a specific URL like http://www.foobar.com/foo/1001
Anonymous user can see this page but cannot post a comment in this page. Comment posting part is secured by Spring security.
User clicks login. It pops up a login window or redirect it to login page.
The user chooses to sign in with Facebook ID.
After user signed in using FB, it redirects the user to http://www.foobar.com/foo/1001 with authorization.
I was wondering how I can do that using Spring Social. Thanks a lot!!
Have you actually tried it to see if it works? Spring security does this automatically.
If you are an anonymous user and attempt to access a resource that requires a certain permission, spring security will store the attempted URL and redirect you to the login page. After successful login it fetches the attempted URL back and redirects you there.
I have only managed to do this by copy/pasting code which spring security uses to do this job.
CAVEAT: I am using ProviderSignInController to provision accounts and sign in.
ProviderSignInController permits the use of a SignInAdapter to manually login local user account based on the SocialConnection
In the signIn method:
public String signIn(String userId, Connection<?> connection, NativeWebRequest request)
I have the following code:
HttpServletRequest req = (HttpServletRequest)request.getNativeRequest();
HttpServletResponse resp = (HttpServletResponse)request.getNativeResponse();
RequestCache rc = new HttpSessionRequestCache();
SavedRequest savedRequest = rc.getRequest(req, resp);
String targetUrl = savedRequest.getRedirectUrl();
if(targetUrl != null){
log.info("Redirecting to DefaultSavedRequest Url: " + targetUrl);
new DefaultRedirectStrategy().sendRedirect(req, resp, targetUrl);
hasSentRedirect = true;
}
I had to dig through the code of SavedRequestAwareAuthenticationSuccessHandler to see how this works as part of spring security.
I am disappointed that ProviderSignInController isn't really linked to Spring Security at all. And so we must hack our way around to get the same functionality.
I have also found that login events aren't posted either.
I have asked about this recently: Should I use both SocialAuthenticationFilter and ProviderSignInController together
I am trying to create a RestEasy client for services host in JBPM server. The service url is always redirecting to a form based login screen which expects j_username and j_password.
I need to login to the service and also have to store the cookies to avoid authentication everytime. Please suggest the best implementation to achieve this.
Now all the service calls ends up in returning the login html page.
I tried some of the solutions posted here, but not works in my scenario.
RESTEasy client framework authentication credentials
RestEasy Client Authentication and HTTP Put with Marshalling
First, write an authetication servlet (where you can intercept the login credentials and store them to your cookie):
#WebServlet(urlPatterns = {"/security_check"})
public class AuthenticationServlet extends HttpServlet
{
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throwsServletException, IOException
{
request.login(userName, userPassword);
StoreInCookieMethod(request.getUserPrincipal().getName(), userPassword);
response.sendRedirect(request.getContextPath() + "/protectedResourceUrlPattern/");
}
}
in the login_form, map the action to the servlet URL
eg:
<form method="post" action="security_check">
for all other requests other than login, define a url pattern(eg protectedResourceUrlPattern) and autheticate using the credentials from cookie