If I have multiple CF8 servers, can a user login on one server, but share the login credential among all servers (no re-login required)?
Maybe question is about sharing session? This can be done using serialized J2EE sessions or using shared client variables.
For example, this can be done in following way.
Create empty database on one of servers (I've created MySQL one). Create datasources pointing to this DB on all CF servers. Use this datasource as Server Settings > Client Variables > client sessions storage with name SharedSessions (we'll use it later).
If we're using cflogin in Application.cfm on all servers, it's code can look this (simplified) way:
<cfapplication
name="shared_session_test"
sessionManagement="true"
clientmanagement="true"
clientstorage="SharedSessions" />
<cflogin>
<cfif IsDefined( "cflogin" ) and cflogin.name eq "admin" and cflogin.password eq "admin">
<cfset user_roles = "administrators" />
<cfset user_name = cflogin.name />
<cfset user_password = cflogin.password />
</cfif>
<cfif IsDefined( "user_roles" )>
<!--- push login params into shared client scope --->
<cfset CLIENT.user_roles = user_roles />
<cfset CLIENT.user_name = user_name />
<cfset CLIENT.user_password = user_password />
<cfelseif IsDefined( "CLIENT.user_roles" )>
<!--- restore login params from shared client scope --->
<cfset user_roles = CLIENT.user_roles />
<cfset user_name = CLIENT.user_name />
<cfset user_password = CLIENT.user_password />
</cfif>
<cfif IsDefined( "user_roles" )>
<cfloginuser name="#user_name#" password="#user_password#" roles="#user_roles#">
<cfelse>
<!--- authentication failed - send back 401 --->
<cfsetting enablecfoutputonly="yes" showdebugoutput="no">
<cfheader statuscode="401">
<cfheader name="WWW-Authenticate" value="Basic realm=""MySecurity""">
<cfoutput>Not authorized</cfoutput>
<cfabort />
</cfif>
</cflogin>
<cfoutput><p>other.server.com</p></cfoutput>
Now these show the same on both servers:
<cfdump var="#getAuthUser()#">
<cfdump var="#CLIENT#">
Sure, there's much to do here to make process better and more secure, just described the general idea.
Hope this helps.
Related
I am using CFLDAP to have users get authenticated using active directory. I am trying to write an if statement in case the users information does not come back as authenticated. I thought I could check by using <cfif AuthenticateUser.RecordCount gt 0> which is working as long as the information is correct but if the wrong information is entered and nothing is authenticated it is not running the else statement. Any help with this would be greatly appreciated!
<cfldap action="query"
name="AuthenticateUser"
attributes="dn,mail,givenname,sn,samaccountname,memberof"
start="DC=domain,DC=net"
filter="(&(objectclass=user)(samAccountName=#trim(form.user_name)#))"
server="servername"
Port="389"
username="tc\#trim(form.user_name)#"
password="#trim(form.user_pass)#">
<cfoutput>#AuthenticateUser.RecordCount#</cfoutput>
<!--- Get all records from the database that match this users credentials --->
<cfquery name="userVerify" datasource="test">
SELECT *
FROM dbo.Users
WHERE user_name = <cfqueryparam value="#AuthenticateUser.samaccountname#" cfsqltype="cf_sql_varchar" />
</cfquery>
<cfif AuthenticateUser.RecordCount gt 0>
<!--- This user has logged in correctly, change the value of the session.allowin value --->
<cfset session.allowin = "True" />
<cfset session.employee_number = userVerify.employee_number />
<!--- Now welcome user and redirect to "index.html" --->
<script>
self.location="../dashboard/dashboard.cfm";
</script>
<cfelse>
<!--- this user did not log in correctly, alert and redirect to the login page --->
<script>
alert("Your credentials could not be verified, please try again!");
self.location="Javascript:history.go(-1)";
</script>
</cfif>
I have also tried: <cfif len(AuthenticateUser)>
This is how I do it. I try to run a query against our domain using the supplied username and password. If the supplied username and password are not valid, an error is generated.
<cftry>
<cfldap action="Query"
name="ADResult"
attributes="dn"
start="DC=domain,DC=net"
filter="sAMAccountName=administrator"
server="servername"
scope = "subtree"
username="#arguments.username#"
password="#arguments.password#" />
<cfset isAuthenticated = true />
<cfcatch type="any">
<cfset isAuthenticated = false />
</cfcatch>
</cftry>
<cfreturn isAuthenticated />
I wrap this up in a function called "authenticate" and expose it via a web service that I call from my apps. If I then need additional details about the user (mail, givenName, etc), I have another function in the same web service that I will call after I am sure the user has been authenticated. Note that in this other function I'm using my administrator username and password to run the query.
<cfldap action="Query"
name="ADResult"
attributes="mail,givenName"
start="DC=domain,DC=net"
filter="sAMAccountName=#arguments.username#"
server="servername"
scope = "subtree"
username="administrator"
password="myAdminPassword" />
I take the results of this, populate a query object or a structure, and return that to the calling function.
So the entire process sort of looks like this:
<cfset objAD = createobject("webservice", "http://mywebservice.com") />
<cfset isAuthenticated = objAD.authenticate(form.username, form.password) />
<cfif isAuthenticated>
<cfset userDetails = objAD.getUserDetails(form.username)>
</cfif>
Hope this helps.
This is a formatted comment. You are trying to do too much at once. Go one step at a time. Start with this:
<cfdump var="before cfldap tag<br />">
<cfldap action="query"
name="AuthenticateUser"
etc
>
<cfdump var="after cfldap tag<br />">
<cfdump var = "#AuthenticateUser#">
<cfdump var="after cfdump<br />">
Run this code with both valid and not valid credentials. Look at what you get. React accordingly.
I think it throws an error when the query fails. Try this:
<cftry>
<cfldap action="query"
name="AuthenticateUser"
attributes="dn,mail,givenname,sn,samaccountname,memberof"
start="DC=domain,DC=net"
filter="(&(objectclass=user)(samAccountName=#trim(form.user_name)#))"
server="servername"
Port="389"
username="tc\#trim(form.user_name)#"
password="#trim(form.user_pass)#">
<cfset LoginStatus = "Success">
<cfcatch type="any">
<cfset LoginStatus = "Failed">
</cfcatch>
</cftry>
Then your cfif would be something like this:
<cfif LoginStatus eq "Success">
<!--- This user has logged in correctly, change the value of the session.allowin value --->
<cfset session.allowin = "True" />
<cfset session.employee_number = userVerify.employee_number />
<!--- Now welcome user and redirect to "index.html" --->
<script>
self.location="../dashboard/dashboard.cfm";
</script>
<cfelse>
<!--- this user did not log in correctly, alert and redirect to the login page --->
<script>
alert("Your credentials could not be verified, please try again!");
self.location="Javascript:history.go(-1)";
</script>
</cfif>
I think this works on CF9.
My dept. has just bought CF10 and I'm finally updating my existing web app to CF10 from CF8.
My first problem with CF10 is using session variables. When using the lower versions of CF (CF4 to CF8) I have never had any problem setting up session variables and getting or using these variables in other pages after a successful login. With CF 10 it seems setting session variables and using them in other pages are major problems. I'm not sure what have I done wrong in the code.
First I'm setting the session in my Application.cfc this way:
<cfcomponent displayname="Application" output="true">
<cfset THIS.Name ="MyNewApp"/>
<cfset THIS.ApplicationTimeout = CreateTimeSpan(0,0,20,0) />
<cfset THIS.SessionManagement ="YES"/>
<cfset THIS.SessionTimeout = CreateTimeSpan( 0, 0, 20, 0 ) />
<cfset THIS.SetClientCookies = false />
<cffunction name="OnApplicationStart" access="public" returntype="boolean"
output="false">
<cfset application.Main_DSN = "TESTDB">
<cfreturn true />
</cffunction>
<cffunction name="onApplicationEnd" output="false">
<cfargument name="applicationScope" required="true">
</cffunction>
<cffunction name="OnSessionStart" access="public" returntype="void" output="false"
hint="Fires when user session initializes.">
<cfset session.loggedin = "NO">
<cfset session.username = "">
<cfset session.userrights = "">
<cfset session.usergroup = "">
</cffunction>
</cfcomponent>
After login, user is validated and set values to those session.variables:
........user validation codes here......................
<cfif mylogin NEQ true>
<cflocation url="/login/login.cfm">
<cfabort
<cfelse>
<cfset session.loggedin="Yes">
<cfset session.username="#Trim(Form.username)#">
<CFSET qUserRights = LoginObj.getUserRights('#Trim(Form.username)#')>
<cfset session.userrights = qUserRights><!--- it's a query --->
<CFSET qUserGroup = LoginObj.getUserGroup('#Trim(Form.username)#')>
<cfloop query="qUserGroup">
<cfset session.usergroup = user_group>
<cfbreak>
</cfloop>
<!--- ******* ?????????????????????????
When I do cfdump in at this level, I can see that all of these session variables have
been assigned to their values.
But these session variables are not accessible from other pages. Other pages still show
these session variable without its value.
So, when I use these cfdumps in the index.cfm it is shown as they're not yet assigned
with any values ********* --->
<cfdump var="#session.loggedin#">
<cfdump var="#session.username#">
<cfdump var="#session.userright#">
<cfdump var="#session.usergroup#">
</cfif>
In index.cfm, Before Login I got:
session.loggedin = NO
session.username = ["empty string"]
session.userrights = ["empty string"]
session.usergroup = ["empty string"]
After a successful Login:
session.loggedin = NO
session.username = ["empty string"]
session.userrights = ["empty string"]
session.usergroup = ["empty string"]
Have I done something wrong? This code works on CF8.
I need to mention: CF10 is in Linux and my web app is under https not http. But these session variables should be shared between http and https because some older pages are still in http and can not be moved to https.
I do not have a direct answer to this question. However, the problem is not only in CF10. I am experiencing this in CF8. I create session variables in my application.cfc however they cannot be seen (accessed) in other pages. I believe in your case you may want to consider case sensitive checks since you are on a Linux platform as rudimentary as this may seem if all else fails.
Hi I'm very new with ColdFusion 10 especially with Application.cfc. It is very confusing.
I created Application.cfc and inside this cfc I created the following:
My questions are:
1. Why do I get session error? (see my codes below)
2. What should I put in sessionEnd function?
<!--- Application.cfc --->
<CFCOMPONENT displayname="Application" output="true">
<cfset THIS.Name = "MyTestApp" />
<cfset THIS.ApplicationTimeout = CreateTimeSpan(0,0,60,0) />
<cfset THIS.SessionManagement = true />
<cfset THIS.SessionTimeout = CreateTimeSpan( 0, 0, 30, 0 ) />
<cfset THIS.SetClientCookies = false />
<cfset THIS.SetClientCookies = false />
<cffunction name="OnApplicationStart" access="public"
returntype="boolean" output="false">
<cfset application.Main_DSN = "MyTestDB">
</cffunction>
<cffunction name="onApplicationEnd" output="false">
<cfargument name="applicationScope" required="true">
</cffunction>
<cffunction name="OnSessionStart" access="public" returntype="void" output="false"
hint="Fires when user session initializes">
<cfset session.loggedin = "NO">
<cfset session.username = "">
<cfset session.userrights = "">
<cfset session.usergroup = "">
</cffunction>
<!--- After user login, I have checklogin.cfm --->
<cfif mylogin NEQ true><!--- Login failed, go redirect to login page --->
<cflocation url="login.cfm">
<cfelse>
<cfset session.loggedin = "YES"><!--- ??? error: see below --->
<cfset session.username = "#Trim(Form.username)#">
<cfset session.userrights = "#Trim(Form.userrights )#">
<cfset session.usergroup = "#Trim(Form.usergroup)#">
</cfif>
<cffunction name="onSessionEnd">
<!--- Not sure what can I put in here????? --->
</cffunction>
Your login code is outside any of the event handlers in your Application.cfc file, so that code will run first... before any of the event handlers!
The execution sequence of code in Application.cfc is:
code outside of any event handler (irrespective of where it is in the file)
onApplicationStart()
onSessionStart()
onRequestStart()
etc
So you cannot have code referencing the session scope (or application scope for that matter) outside the other event handlers. You can only start using session variables once onSessionStart() has fired. Not before.
What is the error message that you are getting?
You can really put anything in the session end. Anything that you would need to run to clean up after a session.
Maybe you want to update a log or send an email, clear a cookie, or redirect to a certain page.
EDIT:
Is everything else in the Application.cfc working for you? It seems like the onSessionStart event is not firing.
EDIT 2:*
Sorry for doing this via an answer but I need more rep to leave comments.
The session should start as soon as you connect to the application, you do not need to wait to be "logged in" as in verify credentials.
If the session variables do not exist then the event is not firing for some reason. Make sure you have the file name correctly and it is in the root folder of the application.
EDIT 3:
Your login code is not in the onSessionStart function, not in any function. Unless I misunderstood your comment and you were saying that code section is in the "checklogin.cfm" file and not in the Application.cfc file.
EDIT 4:
I need to jump on a client call but I can help some more after. We might need to take a look at part of the checklogin.cfm file.
EDIT 5:
Any luck?
EDIT 6:
Sorry for the delay, volume is ramping up this afternoon.
At this point I think I would either need to see the code that is doing the validation checking or ask if you are sure the validation is working correctly.
I assume you are connecting to a database, if you take the query you are using to verify the login credentials and run it in SQL server or whatnot inserting the values you would type into the form, do you get any results?
EDIT 7:
Figure it out, OP?
My application pulls lots of data from different applications according to the selected scopes. For e.g. Org level and SubOrg level scopes, this can cause to bring server down and everyday causes server crashing and timeouts.
So I wanted to know whether wrapping cfthread around my cfhttp will solve my timeout problem?
<cfinclude template="fundedScopes.cfm">
<!--- Call the funded scopes --->
<cfset dynVarName = "funded" & bizforShort>
<cfif structKeyExists(variables,dynVarName)>
<cfset howManyCustomScopes = listLen(structkeylist(variables[dynVarName],"|" ),"|" )>
<cfmodule template="#Request.Library.CustomTags.VirtualPath#Scheduler_LogDetail.cfm"
Step="Funded Level Cache" Detail="Custom Scopes to be cached: #howManyCustomScopes#"
LogData=""></cfmodule>
<cfloop collection="#variables[dynVarName]#" item="t">
<cfset tempurl = variables[dynVarName][t]["url"]>
<cfset tempurl = tempurl & "&retainCache=1">
<cfoutput>
<cfhttp url="#tempurl#" method="GET" resolveurl="false" timeout="3000">
#tempurl#<br>
<cfset scopesCachedCounter = scopesCachedCounter + 1>
<cfmodule template="#Request.Library.CustomTags.VirtualPath#Scheduler_LogDetail.cfm" Step="Funded Scopes Cache" Detail="#scopesCachedCounter#.- #t#" LogData="#tempurl#"></cfmodule>
</cfoutput>
</cfloop>
</cfif>
apologies if this has been asked before but i couldn't find anything that could answer my question.
We have a Coldfusion script that runs from our website and queries an external dsn in our office.
Problem is that the server is located in rural england and sometimes the server is unavailable (thanks to our unreliable UK ISP!!)
Is there a command in coldfusion that could query or ping an external dsn so I can wrap the whole script in a cfif statement and get an email if it fails to connect?
This is an extension to a comment on duncan's answer, but can't put code blocks in comments, so...
<cfset TargetHost = "0.0.0.0" />
<cfset PingAttempts = 4 />
<cfif find('Windows',Server.Os.Name)>
<cfset Args = "-n #PingAttempts# #TargetHost#" />
<cfelse>
<cfset Args = "-c #PingAttempts# #TargetHost#" />
</cfif>
<cfexecute name="ping" arguments=#Args# variable="PingResult" timeout=10 />
<cfif PingResult CONTAINS "100% packet loss"
OR PingResult CONTAINS "100% loss"
>
[send alert]
</cfif>
<cfdump var=#PingResult# />
(In general, I'd still go with checking via an actual query - pinging only confirms the machine is online, not that the database is responding.)
JFGI:
<cfexecute name="C:\winnt\system32\ping.exe" arguments="#request.myIP#" variable="myPing" timeout="8"></cfexecute>
Or on Linux/Unix:
<cfexecute name="ping" arguments="#request.myIP# -c 3" timeout="10" variable="myPing" />
<cfif myPing contains "Request timed out">
<cfmail ...>
<cfelse>
[do something else]
</cfif>
Or http://www.bennadel.com/blog/751-Learning-ColdFusion-8-Ping-User-Defined-Function-Inspired-By-Ray-Camden-.htm
To find out if the datasource works just try to use it:
<cftry>
<cfquery datasource="external" timeout=10 >
SELECT 1
</cfquery>
<cfcatch>
<cfif [timeout error]>
<cfmail ...>No response in 10 seconds</cfmail>
<cfelse>
[do something else]
</cfif>
</cfcatch>
</cftry>
Since that doesn't appear to work, another option might be:
<cfthread action="run" name="QueryThread">
<cfquery datasource="external">SELECT 1</cfquery>
</cfthread>
<cfthread action="run" name="CheckThread">
<cfthread action="sleep" duration="10000" />
<cfif cfthread.QueryThread.Status NEQ 'COMPLETED'>
[handle error]
<cfthread action="terminate" name="QueryThread" />
</cfif>
</cfthread>
Same concept, but using multiple threads should mean that even if the query is too deep for CF to break, you can still trigger the email sending after ten seconds.