How to trim username from email id in terraform - terraform

How to drop everything after # in email id in terraform
count = length(local.admin_users)
username = "${trimspace(local.admin_users[count.index])}_default"
It gives me test#gmail.com_default
I want test_default
How can this be accomplished in terraform

You could split the admin_user based on # character and use its first part:
username = "${split("#", trimspace(local.admin_users[count.index]))[0]}_default"

Related

MalformedPolicyDocument error on aws policy creation - terraform apply

While inserting new aws IAM policy rule on terraform, terraform plan passes
as terraform apply fails on the statement ID.
data "aws_iam_policy_document" "db_iam_policy_document" {
version = "2012-10-17"
statement {
actions = ["rds:DeleteDBInstance"]
effect = "Deny"
resources = [
"arn:aws:rds:us-west-2:123456789:db:*"
]
condition {
test = "StringEquals"
variable = "rds:db-tag/environment"
values = [
"production"
]
}
sid = "don't_delete_production_dbs !"
}
}
The error presented on my CI/CD pipeline as the following:
Error: error updating IAM policy arn:aws:iam::123456789:policy/my_policy_name:
MalformedPolicyDocument: Statement IDs (SID) must be alpha-numeric.
Check that your input satisfies the regular expression [0-9A-Za-z]*
According to aws iam documentation The Sid element on aws policy ( statement id - which helps us to improve and convey a better documenation and readability to our iam rules ) supports ASCII uppercase letters (A-Z), lowercase letters (a-z), and numbers (0-9).
we need to change the sid attibute following the right rules and get rid of the incorrect chars ( on this example space, underscore,comma and exclamation mark ).
sid = "productionDBDeletionIsProhibited"

can I call a function to set my USERNAME_FIELD = ''?

can I call a function in USERNAME_FIELD = '' to create an optional choice for login, using email or phone number? if yes how?
yes, you can
you can write special login function in your view and use query like this :
user = User.objects.filter(Q(email=value)|Q(username=value)).first()
login(request, user)
I use Q django db functions to complex query and I can use Or in my queries for example in up code I filter email equal by value or username equal by value so if uaer enter username or email I can find him
in other ways I can use two query but its not common
like this :
user_by_username=User.objects.filter(usernsme=value).first()
if user_by_username:
login(request,user)
else:
user_by_email=User.objects.filter(email=value).first()
if user_by_email:
login(request,user_by_email)
and default user model hasn't mobile field you can save mobile as username or create special usermodel
or create new model for your user profile

Terraform: How to remove a user resource created from an array/list?

I have a file users.tf file that creates the admin users for aws. It does so by defining a list (e.g. users = ["bob", "john", "tom"])
and then iterating over them with the aws_iam_user resource using the count functionality in terraform, like so:
resource "aws_iam_user" "user" {
count = length(local.users)
name = local.users[count.index]
}
the issue here, is that if I remove the first element of the array ("bob" from the above example), what terraform will suggest to do after issuing terraform plan, instead of deleting bob, is to change bob to john, change john to tom, and delete tom.
like so:
# aws_iam_user.user[0] will be updated in-place
~ resource "aws_iam_user" "user" {
arn = "arn:aws:iam::5555555:user/bob"
force_destroy = false
id = "bob"
~ name = "bob" -> "john"
path = "/"
tags = {}
unique_id = "BLABLABLA11111"
}
# aws_iam_user.user[1] will be updated in-place
~ resource "aws_iam_user" "user" {
arn = "arn:aws:iam::5555555:user/john"
force_destroy = false
id = "john"
~ name = "john" -> "tom"
path = "/"
tags = {}
unique_id = "BLABLABLA22222"
}
# aws_iam_user.user[2] will be destroyed
- resource "aws_iam_user" "user" {
- arn = "arn:aws:iam::5555555:user/tom" -> null
- force_destroy = false -> null
- id = "tom" -> null
- name = "tom" -> null
- path = "/" -> null
- tags = {} -> null
- unique_id = "BLABLABLA3333" -> null
this will result in john getting the arn of bob, and tom getting the arn of john. which is undesirable.
I tried using the very new feature (released 19 hours prior to the writing of this question) of for_each loop instead of count, and defining the keys as the original index numbers, hoping that terraform will consider them as the same resource.
yeah well, no such luck:
...
# aws_iam_user.user[1] will be destroyed
...
# aws_iam_user.user["1"] will be created
...
I will summarize my question:
Is there any way to delete a resource (specifically aws_iam_user), when that resource was created by iterating over a list, such that all the remaining resources stay the way they were?
What you have seen here is the situation that the count documentation warns about in its final paragraph:
Note that the separate resource instances created by count are still identified by their index, and not by the string values in the given list. This means that if an element is removed from the middle of the list, all of the indexed instances after it will see their subnet_id values change, which will cause more remote object changes than were probably intended. The practice of generating multiple instances from lists should be used sparingly, and with due care given to what will happen if the list is changed later.
Fortunately, this is the very problem the for_each feature is intended to solve. Though, in order to use it effectively it's important to choose meaningful unique keys in the map you pass to for_each:
resource "aws_iam_user" "user" {
for_each = { for name in local.users : name => name }
name = each.value
}
This will cause Terraform to track instance identifiers like aws_iam_user.user["john"] rather than aws_iam_user.user[1].
You have existing count-based instances in your state though, so it'll take some migration steps to get there. Unfortunately Terraform doesn't have enough information to automatically correlate your existing index-based addresses with the new name-based ones, but by using your existing list with a separate one-off script you can tell Terraform how to translate these by running a command like this for each entry in the list:
terraform state mv 'aws_iam_user.user[1]' 'aws_iam_user.user["john"]'
After that, Terraform will track these objects by name and thus adding and removing names will affect only the objects relating to the names you changed.
If you aren't ready to do a full switch to for_each right now, you can use a similar strategy with a one-off script to "heal" the hole created by removing an item from your list:
# First, Terraform must "forget" the user that you removed
terraform state rm 'aws_iam_user.user[0]'
# Then renumber the subsequent items to correlate with their new
# positions in the list.
terraform state mv 'aws_iam_user.user[1]' 'aws_iam_user.user[0]'
terraform state mv 'aws_iam_user.user[2]' 'aws_iam_user.user[1]'
# etc, etc
This will of course be a rather tedious, error-prone process to do manually if you have more than a small number of users, so better to write a small program to generate the script.

freeradius (MySQL config) adding custom attributes to the reply-item

I've run into a dead end while trying to set up customized attributes as a reply item (I want custom information added to the "access accept" packet).
While trying to achieve this I came across this entry:
# If you want to add entries to the dictionary file,
# which are NOT going to be placed in a RADIUS packet,
# add them to the 'dictionary.local' file.
#
# The numbers you pick should be between 3000 and 4000.
# These attributes will NOT go into a RADIUS packet.
#
# If you want that, you will need to use VSAs. This means
# requesting allocation of a Private Enterprise Code from
# http://iana.org. We STRONGLY suggest doing that only if
# you are a vendor of RADIUS equipment.
#
# See RFC 6158 for more details.
# http://ietf.org/rfc/rfc6158.txt
So I understand how the usual approach should be.
However my infrastructure is set up in stages and the radius server in question is already placed on the "inside", so I don't see why I shouldn't be able to set or overwrite unused attributes on both ends of this second internal authentication step.
Googleing around I found several threads on how to set this type of thing up with a users-file based approach on 1.x versions of Freeradius, not so much for any of the newer releases.
Is what I'm proposing still possible with freeradius-server-3.0.10 ?
And if so, how should I go about implementing this?
Current state:
I've added my attribute "faculty" to the dictionary (mapping the set integer from the DB to a string set in directory ie. Ei & MECH) and the respective DB, causing the radius server to find and evaluate the attribute set in "radreply" (here: := MECH) and "radgroupreply" (here += EI).
...
rlm_sql (sql1): Reserved connection (5)
(1) sql1: EXPAND SELECT id, username, attribute, value, op FROM radcheck WHERE username = '%{SQL-User-Name}' AND active > '0' AND active < '3' ORDER BY id(1) sql1: --> SELECT id, username, attribute, value, op FROM radcheck WHERE username = '*username*' AND active > '0' AND active < '3' ORDER BY id
(1) sql1: Executing select query: SELECT id, username, attribute, value, op FROM radcheck WHERE username = '*username*' AND active > '0' AND active < '3'ORDER BY id
(1) sql1: User found in radcheck table
(1) sql1: Conditional check items matched, merging assignment check items
(1) sql1: Cleartext-Password := "*password*"
(1) sql1: EXPAND SELECT id, username, attribute, value, op FROM radreply WHERE username = '%{SQL-User-Name}' ORDER BY id
(1) sql1: --> SELECT id, username, attribute, value, op FROM radreply WHERE username = '*username*' ORDER BY id
(1) sql1: Executing select query: SELECT id, username, attribute, value, op FROM radreply WHERE username = '*username*' ORDER BY id
(1) sql1: User found in radreply table, merging reply items
(1) sql1: faculty := MECH
(1) sql1: EXPAND SELECT groupname FROM radusergroup WHERE username = '%{SQL-User-Name}' ORDER BY priority
(1) sql1: --> SELECT groupname FROM radusergroup WHERE username = '*username*' ORDER BY priority
(1) sql1: Executing select query: SELECT groupname FROM radusergroup WHERE username = '*username*' ORDER BY priority
(1) sql1: User found in the group table
(1) sql1: EXPAND SELECT id, groupname, attribute, Value, op FROM radgroupcheck WHERE groupname = '%{sql1-SQL-Group}' ORDER BY id
(1) sql1: --> SELECT id, groupname, attribute, Value, op FROM radgroupcheck WHERE groupname = 'vid100' ORDER BY id
(1) sql1: Executing select query: SELECT id, groupname, attribute, Value, op FROM radgroupcheck WHERE groupname = 'vid100' ORDER BY id
(1) sql1: Group "vid100": Conditional check items matched
(1) sql1: Group "vid100": Merging assignment check items
(1) sql1: EXPAND SELECT id, groupname, attribute, value, op FROM radgroupreply WHERE groupname = '%{sql1-SQL-Group}' ORDER BY id
(1) sql1: --> SELECT id, groupname, attribute, value, op FROM radgroupreply WHERE groupname = 'vid100' ORDER BY id
(1) sql1: Executing select query: SELECT id, groupname, attribute, value, op FROM radgroupreply WHERE groupname = 'vid100' ORDER BY id
(1) sql1: Group "vid100": Merging reply items
(1) sql1: Tunnel-Type = VLAN
(1) sql1: Tunnel-Medium-Type = IEEE-802
(1) sql1: Tunnel-Private-Group-Id = "100"
(1) sql1: faculty += EI
rlm_sql (sql1): Released connection (5)
...
The keen observer will also notice some changes to the "radcheck" query, but this change is not related to the topic at hand.
So the Server gets the information, however I've not found a way to include it to the reply yet.
(1) Sent Access-Accept Id 81 from **IP-Radius-server**:*port* to **IP-supplicant**:*port* length 0
(1) Tunnel-Type = VLAN
(1) Tunnel-Medium-Type = IEEE-802
(1) Tunnel-Private-Group-Id = "100"
(1) Finished request
Any help or pointers would be appreciated :)
Felix
To anyone having similar problems.
I've come up with a workaround that works for me.
As described above it really is a lot of fuss to build a custom attribute.
What you can use though, is attribute 18 (Reply-Message) to convey information.
I went about this by adding to: .../raddb/sites-available/default in the "post-auth" section.
if (&reply:faculty && &request:NAS-IP-Address == *IP-WEBSERVER*) {
update reply {
Reply-Message += "Faculty: %{reply:faculty}"
}
}
Which adds "faculty" information if it can be found in either the radreply or the radgroupreply if and only if the supplication comes via the sepcified "webserver". Using the freeradius operator arithmetic you can also weight the reply (for me: radreply := radgroupreply +=).
This works well for freeradius3.0.10.
I consider this thread closed - Felix
You need to define your custom attribute as a VSA (Vendor specific attribute). Attributes above 255 in the standard RADIUS dictionary will not be encoded in proxied requests, or in replies, that is because the attribute field is only 1 byte wide.
If you want to do it properly you'll need to request an IANA PEN (Private Enterprise Number) http://pen.iana.org/pen/PenApplication.page for your organisation (after checking there isn't already one assigned http://www.iana.org/assignments/enterprise-numbers/enterprise-numbers).
You can then define your own vendor dictionary, and add your own attributes with numbers between 1-255.
Here's a nice short one you can use as an example: https://github.com/FreeRADIUS/freeradius-server/blob/v3.1.x/share/dictionary.bt
You don't need a separate file for your vendor dictionary, you just need to copy the relevant lines into raddb/dictionary.
If you don't care about doing it properly, look through the PEN assignments to find a defunct company and use their PEN.

BDD: SpecFlow - Scenario Outline Behaviour Not As Expected

Using scenario outlines in SpecFlow, e.g.
Scenario Outline: Invalid Login Details
Given some pre-conditions...
When user "Larry" enters username <username> and password <password>
Then the message "Invalid Login Details" should be displayed
Examples:
|username|password|
|larry06 | |
|larry06 |^&*%*^$ |
|%^&&** |pass123 |
| |pass123 |
I expected that the "When" step would be evaluated as such:
public void WhenUserEntersUsernameAndPassword(String username, String password){}
And that the scenario would be run 4 times - for each row of the table, passing the values as required. That's not the case.
Instead, SpecFlow creates 1 of 4 required step definitions:
[When(#"""(.*)"" provides the following new username larry(.*) and password ")]
public void WhenUserEntersUsernameLarryAndPassword(string p0, int p1)
{
//TODO
}
And to get the remaining 3 to 'work' I need to manually write methods explicitly matching other values in the table.
I've since realised that I can just say:
When "Larry" enters username "<username>" and password "<password>"
And I get:
[When(#"""(.*)"" provides the following ""(.*)"" and ""(.*)""")]
public void WhenUserEntersUsernameAndPassword(string p0, string name, string pass)
{
//TODO
}
Perfect.
But all documentation seems to suggest I don't need "" and that should just work (e.g. https://github.com/cucumber/cucumber/wiki/Scenario-outlines). I note:
"Your step definitions will never have to match a placeholder. They will need to match the values that will replace the placeholder"
I just don't really see the value of writing separate step definitions for each line of the table.
Is this nuance specific to SpecFlow?
When "Larry" enters username <username> and password <password>
will match
[When(#"""(.*)"" enters username (.*) and password (.*)")]
public void WhenEntersUsernameAndPassword(string p0, string name, string pass)
{
//TODO
}
so the documentation is fine.
The problem you experienced is that the auto generation of step text doesn't anticipate what regexs to insert without the "..." - which I guess it must be using as an indicator that you are passing interchangable strings - matchable with "(.*)", but if you don't want the quotes, you can still manually correct it just fine.

Resources