Keycloak - template for handling an already logged in user - keycloak

Using keycloak 11 I tried to find the page for the already logged in user.
I want to customize this page but I fail to find it.
I looked into the message to find the message, and I did its called alreadyLoggedIn.
I tried looking into each template belonging to the base/login folder but I still didn't find the variable. So I supposed its set somewhere in the code but I didn't find anything in the doc or the forums.
anyone please provide the template name and/or its location in the keycloak repo ?

The page you are looking for is template.ftl. The content of alreadyLoggedIn is in h1#kc-page-title and set by a nested header.

The info.ftl page is the one being used for ALREADY_LOGGED_IN message. The template.ftl is never directly used for showing any page from what I know.
You can see from the source code
/**
* Verifies that the authentication session has not yet been converted to user session, in other words
* that the user has not yet completed authentication and logged in.
*/
public static <T extends JsonWebToken> void checkNotLoggedInYet(ActionTokenContext<T> context, AuthenticationSessionModel authSessionFromCookie, String authSessionId) throws VerificationException {
if (authSessionId == null) {
return;
}
UserSessionModel userSession = context.getSession().sessions().getUserSession(context.getRealm(), authSessionId);
boolean hasNoRequiredActions =
(userSession == null || userSession.getUser().getRequiredActionsStream().count() == 0)
&&
(authSessionFromCookie == null || authSessionFromCookie.getRequiredActions() == null || authSessionFromCookie.getRequiredActions().isEmpty());
if (userSession != null && hasNoRequiredActions) {
LoginFormsProvider loginForm = context.getSession().getProvider(LoginFormsProvider.class).setAuthenticationSession(context.getAuthenticationSession())
.setSuccess(Messages.ALREADY_LOGGED_IN);
if (context.getSession().getContext().getClient() == null) {
loginForm.setAttribute(Constants.SKIP_LINK, true);
}
throw new LoginActionsServiceException(loginForm.createInfoPage());
// ^^ createInfoPage is being called
}
}

Related

How to prevent infinite retries - Apache Shiro RESTful service

Goal
I am setting up a RESTful webservice, using RESTEasy framework. For security I use Apache Shiro. I want my api to stop accepting requests or timing out persons that login too much.
Problem
Whenever I go some URL with my browser (chrome), I can try to login infinitely many times. Seems a really bad idea to allow this. As a measure, I have made sure to remember the nr of login attempts, for which users cannot login after 3 times. However, with a brute force attack, you could still block all users from loging in. I want a more general solution.
Shiro.ini
[main]
# We store users and passwords inside the realm.
myRealm = com.myproject.shiro.DatabaseRealm
sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
securityManager.sessionManager = $sessionManager
cacheManager = org.apache.shiro.cache.MemoryConstrainedCacheManager
securityManager.cacheManager = $cacheManager
[urls]
/api/version = anon
/api/** = authcBasic
DatabaseRealm
public class DatabaseRealm extends AuthorizingRealm {
#Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
// No clue what to do with this functin. I only use authentication and not authorization, so probably just nothing.
return null;
}
/**
* Check if the user inputted is valid. The user can login if holds:
* 1. Password is correct. (if not, nrOfLogonAttempts++)
* 2. LogonUser.nrOfLogonAttemps is less than 3
* 3. LogonUser.dateEndValid is null or >= today.
* #param authenticationToken Token with basic information.
* #return SimpleAuthenticationInfo
* #throws AuthenticationException Whenever the user cannot login.
*/
#SuppressWarnings("ConstantConditions")
#Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)
throws UnknownAccountException, IncorrectCredentialsException, LockedAccountException, ExpiredCredentialsException {
// Connect with the database.
DbContext context = null;
try {
context = DbContextUtil.getContextFromTomcat();
// Lookup user in the database.
LogonUserMyDao logonUserMyDao = new LogonUserMyDao(context);
LogonuserPojo logonuserPojo = logonUserMyDao.fetchOneByUsername(((UsernamePasswordToken) authenticationToken).getUsername());
if (logonuserPojo == null) {
throw new UnknownAccountException("Could not find user.");
}
// Check password
String plainTextPassword = new String(((UsernamePasswordToken) authenticationToken).getPassword());
if (!BCryptUtil.checkPassword(plainTextPassword, logonuserPojo.getPassword())) {
// We will note this event.
logonuserPojo.setNroflogonattempts(logonuserPojo.getNroflogonattempts() + 1);
logonUserMyDao.update(logonuserPojo);
context.commit();
throw new IncorrectCredentialsException("Incorrect password.");
}
// Check nrOfLogonAttempts
if (logonuserPojo.getNroflogonattempts() >= 2) {
throw new LockedAccountException("Cannot login anymore.");
}
// Check date
if (logonuserPojo.getDateendvalid() != null && DateTimeUtil.isBeforeToday(logonuserPojo.getDateendvalid())) {
throw new ExpiredCredentialsException("Account is expired.");
}
// User is valid, so return some info.
return new SimpleAuthenticationInfo(logonuserPojo.getUsername(), plainTextPassword, getClass().getName());
} catch (SQLException e) {
MyLogger.logError("Could not connect to user database.", e);
throw new AuthenticationException("Could not connect to databse.");
} finally {
if (context != null) {
try {
context.getConnection().close();
} catch (SQLException e) {
MyLogger.logError("Could not close connection", e);
}
}
}
}
}
Are you looking for more general DDOS protection? There are a few options out there depending on where your app is running (for example AWS Shield).
You could also prevent connections from reaching your db with something like this: https://github.com/iTransformers/ddos-servlet-filter (but, that that would still require handling the request in your application)
On the Shiro side of things, counting your attempts is NOT a bad idea, but you need to watch out for the user management side of things (How does a user get unlocked, support request? Wait 30 minutes?) Instead of recording failures, you may just want to record/audit all attempts (excluding the actual password of course). With either option a call to support or an n minute window, this may help provide some context to support or an easy query.

IdentityServer WithCustomUserService on External Login throws nullreference exception

I Implementd a custom userservice to store user data in a database.
Since that I get a NullReferenceException when I try to authenticace with an external provider like facebook.
I can see this stack in the exception which indicates that a value is missing for the loginpage. As A result after clicking on the facebook button i'm standing again at the starting login page.
But I don't know why or which value exactly
I can see that at the end of AuthenticateExternal context.AuthenticateResult.User.Claims contains these claims
my user service looks simplified like this
public override async Task AuthenticateExternalAsync(ExternalAuthenticationContext context)
{
string id = context.ExternalIdentity.Claims.FirstOrDefault(i => i.Type == "id").Value;
var user = await gateway.ByExternalIds(context.ExternalIdentity.Provider, id);
if (user == null)
{
string displayName = context.ExternalIdentity.Claims.FirstOrDefault(i => i.Type.Equals("urn:facebook:name")).Value;
user = new User(context.ExternalIdentity);
await gateway.StoreAsync(user);
}
if (user != null)
{
await gateway.SetLastLogin(user.Subject, DateTimeOffset.Now);
context.AuthenticateResult = new AuthenticateResult(user.Subject, GetDisplayName(user), identityProvider: context.ExternalIdentity.Provider);
}
}
What am I missing?
Found it. This behavior occurs when the method for detemerning if the user ist active returns false.
Task IsActiveAsync(IsActiveContext context)
its little unexpected as I had expected that in this case i would see something like "unknown user" or "inactive user"

Codeigniter Tank_Auth_Social Facebook Login Throwing Exception

Sorry If there is a post like this question, I checked but I couldn’t find any..
I’m using tank_auth_social for Facebook login.
https://github.com/sicsol/Tank-Auth-Social
Also someone mentioned this problem on issues but no reply..
https://github.com/sicsol/Tank-Auth-Social/issues/2
After user giving access from Facebook at first login it throws exception like this.
Fatal error: Uncaught OAuthException: An active access token must be used to query information about the current user. thrown in /home/hayvanse/public_html/application/libraries/facebook/base_facebook.php on line 1058
Yeah so we couldn’t have write token it means that yeah? But when I click to login and it works.
The first one only gives exception due to one problem and its not about Facebook token I think.
I’m really newbie on Facebook connect stuff, I updated Facebook and base_facebook library but didn’t work.
I hope had this problem and could help me. This is based function on this line so I wonder if I just skip exception,I'm really confused and looked for it all night :(
protected function throwAPIException($result) {
$e = new FacebookApiException($result);
switch ($e->getType()) {
// OAuth 2.0 Draft 00 style
case 'OAuthException':
// OAuth 2.0 Draft 10 style
case 'invalid_token':
// REST server errors are just Exceptions
case 'Exception':
$message = $e->getMessage();
if ((strpos($message, 'Error validating access token') !== false) ||
(strpos($message, 'Invalid OAuth access token') !== false)) {
$this->setAccessToken(null);
$this->user = 0;
$this->clearAllPersistentData();
}
}
throw $e;
}
Please update base_book with this function , check the link please. Main problem was getuser was returnin 0. You have to update code like blow on base_Facebook file.(latest sdk)
protected function getCode() {
$server_info = array_merge($_GET, $_POST, $_COOKIE);
if (isset($server_info['code'])) {
if ($this->state !== null &&
isset($server_info['state']) &&
$this->state === $server_info['state']) {
// CSRF state has done its job, so clear it
$this->state = null;
$this->clearPersistentData('state');
return $server_info['code'];
} else {
self::errorLog('CSRF state token does not match one provided.');
return false;
}
}
return false;
}
When using CodeIgniter + Facebook PHP SDK: getUser() always returns 0

ServiceStack OAuth - registration instead login

In servicestack OAuth implementation I only saw possibility to automatically login with eg. facebook account.
But is there abbility to support registration process with facebook login. What I wanted is to let users login to facebook app, and then load their Name, Surname and email and prefill needed text boxes for real registration on my site (since I also have to have mobile phone verification etc.) I don't want user to be authorized and authenticated when he logs in with facebook. Only credentials login should be valid one for full site access.
Edit: I found a solution.
In FacebookProvider.cs
public override bool IsAuthorized(IAuthSession session, IOAuthTokens tokens, Auth request = null)
{
if (request != null)
{
if (!LoginMatchesSession(session, request.UserName)) return false;
}
return tokens != null && session.UserName!=null && !string.IsNullOrEmpty(tokens.AccessTokenSecret);
}
The catch was the && session.UserName!=null part. So we can check if user is logged in using credentials, this will be !=null and user can use all services. If not, this will be ==null and he can only get facebook info from session.
The SocialBootstrap API project shows an example of handling the callback after a successful Authentication by overriding the OnAuthenticated() hook of its custom user session:
I've pulled out, rewrote some and highlighted some of the important bits:
public class CustomUserSession : AuthUserSession
{
public override void OnAuthenticated(IServiceBase authService,
IAuthSession session,
IOAuthTokens tokens,
Dictionary<string, string> authInfo)
{
base.OnAuthenticated(authService, session, tokens, authInfo);
//Populate matching fields from this session into your own MyUserTable
var user = session.TranslateTo<MyUserTable>();
user.Id = int.Parse(session.UserAuthId);
user.GravatarImageUrl64 = CreateGravatarUrl(session.Email, 64);
foreach (var authToken in session.ProviderOAuthAccess)
{
if (authToken.Provider == FacebookAuthProvider.Name)
{
user.FacebookName = authToken.DisplayName;
user.FacebookFirstName = authToken.FirstName;
user.FacebookLastName = authToken.LastName;
user.FacebookEmail = authToken.Email;
}
else if (authToken.Provider == TwitterAuthProvider.Name)
{
user.TwitterName = authToken.DisplayName;
}
}
//Resolve the DbFactory from the IOC and persist the user info
using (var db = authService.TryResolve<IDbConnectionFactory>().Open())
{
//Update (if exists) or insert populated data into 'MyUserTable'
db.Save(user);
}
}
//Change `IsAuthorized` to only verify users authenticated with Credentials
public override bool IsAuthorized(string provider)
{
if (provider != AuthService.CredentialsProvider) return false;
return base.IsAuthorized(provider);
}
}
Basically this user-defined custom logic (which gets fired after every successful authentication) extracts data from the UserSession and stores it in a custom 'MyUserTable'.
We've also overridden the meaning of IsAuthorized to only accept users that have authenticated with CredentialsAuth.
You can use this data to complete the rest of the registration.
Other possible customizations
ServiceStack's built-in Auth persists the AuthData and populates the Session automatically for you. If you want to add extra validation assertions you can simply use your own custom [Authentication] attribute instead containing additional custom logic. Look at the implementation of the built-in AuthenticateAttribute as a guide.

ASP.NET MVC2 - Redirect to Url in overriden controller

I've created a ControllerBase class that overrides the Execute method of the default Controller class. I'm doing this to check the url and pull an associated page from our database. If the page isn't found, I want to redirect to a specific url ("invalid-page"). All is working except the redirect. I've tried to use Response.Redirect("invalid-page"), but it gives me a null reference error. Also tried requestContext.HttpContext.Response.Redirect("invalid-page"), but same error. I'm guessing it doesn't want to let you bypass the MVC process by using a response redirect. And since the override doesn't actually return an ActionResult, I can't just return a Redirect action. Anyone know how I could do a redirect here?
Here's my ControllerBase class:
public class ControllerBase : Controller
{
protected override void Execute(System.Web.Routing.RequestContext requestContext)
{
ViewData.Model = new DynamicPage{ LeftColumnCss = "bg5"};
var friendlyUrl = (string)requestContext.RouteData.Values["friendlyUrl"];
if (friendlyUrl != null && !friendlyUrl.Equals("invalid-page"))
{
var page = PageService.FetchByFriendlyUrl(null, (int?)PageCategoryType.MomMavens, friendlyUrl);
if (page == null)
{
var archivedPage = PageArchiveService.FetchByFriendlyUrl(friendlyUrl);
if (archivedPage != null)
{
page = PageService.FetchById(archivedPage.PageID);
if (page != null)
{
requestContext.HttpContext.Response.Redirect(PageService.GetPageAbsoluteUrl(page));
}
}
}
if (page == null)
{
//This is where I need to figure out how to do a redirect //requestContext.HttpContext.Response.Redirect("invalid-page");
//base.Redirect("invalid-page");
Response.Redirect("contact-us");
return;
}
((DynamicPage)ViewData.Model).CurrentPage = page;
// Allow the page to override the left column class
if (!string.IsNullOrEmpty(page.LeftColumnCssClasses))
{
var classes = page.LeftColumnCssClasses.Split(';');
var index = SubSonic.Sugar.Numbers.Random(0, classes.Length);
if (index == classes.Length)
index--;
((DynamicPage)ViewData.Model).LeftColumnCss = classes[index];
}
}
base.Execute(requestContext);
}
}
EDIT:
Somehow I managed to fix it by changing the line:
if (friendlyUrl != null && !friendlyUrl.Equals("invalid-page"))
to...
if (!friendlyUrl.Equals("invalid-page"))
and then using requestContext.HttpContext.Response.Redirect("invalid-page"), even though that gave me an error before. Not sure why that made a difference. Somehow having pages with blank urls bypass all those checks caused a problem.
Have you tried a Server.Transfer()?
It seems like you could make a change to the RouteValueDictionary and it would work, but I can't remember if it's an readonly collection.
Managed to fix it by changing the if statement slightly. See edit in original post. Still not completely sure what was wrong.