Domains for cookies for office.com

Overview

As part of my security measures, I don’t enable cookies by default for all sites. I enable them per-site, on an as-needed basis. So my whitelist is very large, but I think it helps more than it hinders.

Problem

So modern web applications depends on lots and lots of cookies. The office.com applications depend on a large set of domains. Here is what I have learned so far:
adfs.example.com (my company's ADFS page)
excel.officeapps.live.com
live.com
login.live.com
login.microsoftonline.com
login.windows.net
office.com
office.live.com
office365.com
portal.office.com
powerpoint.officeapps.live.com
products.office.com
word-edit.officeapps.live.com

sshd_config Match AD group

Overview

I use CentOS 7. One of the biggest reasons I join my servers to Active Directory is for the users and groups. Getting sshd_config to work with AD-defined groups is easy and just needs the smallest amount of work.

If you want to use sftp, and have rules for just a specific AD group, you need to specify the group name exactly as it is cased.
[root@amazon|/var/log]# getent group Web_Dev_Grp
web_dev_grp:*:5829038:asmith,rltompki,fkowalks,bangel,lfrederi

So use the “web_dev_grp” as shown in your sshd_config:
Match Group web_dev_grp
ChrootDirectory /var/www
ForceCommand internal-sftp

Overcoming the ADLDS MaxValRange Hard Limit

Introduction

Microsoft Active Directory Lightweight Directory Services (AD LDS), formerly known as Active Directory Application Mode (ADAM), is a directory server application. Some companies use it to store a stripped-down ldap directory of the full AD environment. Whether you need just certain OUs, or just certain attributes available, using ADLDS might solve your problem.
Lots of places online can show you how to use userProxy objects to allow ldap simple binds to the AD LDS instance. LDS, when using userProxy objects, takes the sAMAccountName, finds the object with that attribute, and passes its objectSid and the user-supplied password to the real AD for authentication. So you can accomplish a ldap simple bind. You can even configure ldaps! I have it down to a science now that I’ve done it several times.
But the point of the post today is to show you how to exceed the hard-coded limit for ADLDS in Windows Server 2008 or 2012/2012R2 on the number of multi-value attributes returned for a query.
So AD groups are directory objects of objectClass=group. Group membership is defined by the member attribute of a group. Incidentally, AD (and LDS) provide a derived attribute, “memberof,” on the user (or userProxy) objects that are members of that group. Some applications check either one, but since the memberof is calculated, it doesn’t really matter anyway.
So with a group of your entire userbase, say, “Wiki-Users_Grp,” you might have more than 5000 members.

Adjusting MaxValRange

You probably are already aware of the MaxValRange=5000 value for the attribute lDAPAdminLimits on
CN=Default Query Policy,CN=Query-Policies,CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration,CN=X
ADSI edit showing the navigation to MaxValRange
You can adjust it to whatever number you want. This attribute affects how many attributes will be returned on an object, such as how many members will be returned on the very large group.
ADSI Edit is the application to use to modify this. Make a connection to the configuration context, and navigate to the dn and you can modify its attributes.
If you have more members than the MaxValRange, you will get an attribute returned like this:
member;range=0-4999 (5000): CN=user1,OU=Users,DC=example,DC=com; CN=user2,OU=Users,DC=example,DC=com; [...]
The applications I’ve worked with don’t like that “member;range=” nomenclature. So you have to make the MaxValRange higher so it returns just “member:” for each member.
Well, apparently Windows Server 2008 introduced a hard limit on the number of returned attributes. The MaxValRange will not take effect any higher than 5000.

Changing the hard limit

Qasim Zaidi at TechNet demonstrated how to change the limit: https://blogs.technet.microsoft.com/qzaidi/2010/09/01/override-the-hardcoded-ldap-query-limits-introduced-in-windows-server-2008-and-windows-server-2008-r2/
Use ADSI Edit (adsiedit.msc) and navigate to this DN:
CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration,CN=X
The attribute that should be modified is dSHeuristics. If the value is blank, enter this value:
000000000100000001
Straight from the TechNet article:

If a value has already been set for this attribute, incorporate the existing settings into the new value. When you do this, note the following:
The tenth character from the left must be 1. Twentieth bit must be 2, and so on.
The eighteenth character from the left must be 1.
None of the other characters of the existing value should be changed. For instance, if the existing value is 0000002 then the new value should be 000000200100000001

ADSI Edit showing navigation to dSHeuristics attribute
To ensure this change takes effect, restart the LDS service.
Run an ldap search, and see if the result is what you want for a large group!

References

Weblinks

  1. Overriding default hard limit in Windows Server 2008 https://blogs.technet.microsoft.com/qzaidi/2010/09/01/override-the-hardcoded-ldap-query-limits-introduced-in-windows-server-2008-and-windows-server-2008-r2/
  2. MaxValRange official source https://msdn.microsoft.com/en-us/library/cc223376.aspx
  3. MaxValRange original source from 2014 doc http://support.microsoft.com/en-us/kb/315071

Python script to update value in file

Overview

I do initial system configuration, for images and so on. All the time I have to update arbitrary values in config files. It’s all very repetitive. Sometimes though, instead of being able to use a whole templated config file, I need to modify the one that is in place.

Here today for you is my second-generation solution (the first was a crude shell script). It’s also a part of my bgscripts package available on github.

#!/usr/bin/env python3
# File: /usr/bgscripts/updateval.py
# Author: bgstack15@gmail.com
# Startdate: 2016-10-11 15:59
# Title: Python Script that Updates/Adds Value
# Purpose: Allows idempotent and programmatic modifications to config files
# Package: bgscripts
# History:
#    2016-07-27 wrote shell script 
#    2016-09-14 added the shell script version to bgscripts package
#    2016-10-12 added flags
# Usage:
#   updateval.py /etc/rc.conf "^ntpd_enable=.*" 'ntpd_enable="YES"' --apply
# Reference:
#    /usr/bgscripts/updateval.sh
#    re.sub from http://stackoverflow.com/questions/5658369/how-to-input-a-regex-in-string-replace-in-python/5658377#5658377
#    shutil.copy2 http://pythoncentral.io/how-to-copy-a-file-in-python-with-shutil/
#    keepalive (python script) from keepalive-1.0-5
# Improve:
#    idea: use argparse "nargs" optional input file to use stdin piping/redirection!

import re, shutil, os, argparse
updatevalversion="2016-10-12c"

# Parse parameters
parser = argparse.ArgumentParser(description="Idempotent value updater for a file",epilog="If searchstring is not found, deststring will be appended to infile")
parser.add_argument("-v","--verbose",help="displays output",      action="store_true",default=False)
parser.add_argument("-a","--apply",  help="perform substitution", action="store_true",default=False)
parser.add_argument("-L","--all",    help="replace all instances",action="store_true",default=False)
parser.add_argument("infile", help="file to use")
parser.add_argument("searchstring", help="regex string to search")
parser.add_argument("deststring", help="literal string that should be there")
parser.add_argument("-V","--version", action="version", version="%(prog)s " + updatevalversion)
args = parser.parse_args()

# Configure variables after parameters
verbose = args.verbose
doapply = args.apply
doall = args.all
infile = args.infile
searchstring = args.searchstring
destinationstring = args.deststring

wasfixed = False
outfile = infile + ".updateval-new"

# Make file if it does not exist
if not os.path.isfile(infile): open(infile, "w").close()

# If line exists, replace it
shutil.copy2(infile,outfile) # initialize duplicate file with same perms
with open(outfile, "w") as outf:
   for line in open(infile, "r"):
      p = re.compile(searchstring)
      if p.match(line) and ( not wasfixed or doall ):
         outline = re.sub(searchstring,destinationstring, line).rstrip('\n')
         wasfixed = True
      else:
         outline = line.rstrip('\n')
      if verbose: print(outline)
      #print(outline,file = outf)
      outf.write(outline + '\n')

# Append line if it has not been fixed yet
if not wasfixed:
   with open(outfile, "a") as outf:
      if verbose: print(destinationstring)
      outf.write(destinationstring + '\n')

# replace old file with new file
if doapply:
   shutil.move(outfile,infile)

# Clean up outfile just in case
try:
   os.remove(outfile)
except Exception as e:
   pass

I’ll explain some of the code, just in case the comments don’t do a good job.
Lines 37-42 Whenever i use argparse, I always pull the information out of the argparse object into local variables. If I rename the object or parameter names, I don’t want to have to go update my code everywhere any of those variables are mentioned.

Line 45: This is an arbitrarily named, temporary export file. I wasn’t sure I could do an open() with read-write, so I just duplicate the file and then replace the original (if doapply=true).

Line 48: Basically, touch the file to make sure it exists.

Lines 51-62: This right here (specifically lines 55-56) is the reason I rewrote this in python. This was much harder in shell. Observe around line 61 how the print command was commented out in favor of the outf.write() object method call. The reason I had to give up the print command here was because when I was packaging my bgscripts set for rpm, it was compiling the python with the python2 interpreter, and it was easier to adjust my python code than which python interpreter rpmbuild uses. So a google search got me the output command. I don’t care how I get the task done; I want the task done.

My requirements included appending the destinationstring if the searchstring did not appear in the code. So lines 65-68 handle that.

Lines 70-78 are needed only because of the writing to the other file. If I could write to the original file, I wouldn’t need to do file manipulation.