Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions rails/Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
source 'https://rubygems.org'

gem 'fusionauth_client', '~> 1.51'
gem 'json', '~> 2.6'
gem 'optparse', '~> 0.4'
gem 'base64', '~> 0.2'
74 changes: 74 additions & 0 deletions rails/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# FusionAuth Import Script For Ruby On Rails

A script to import user data from Rails-based authentication systems into FusionAuth. Features duplicate handling, verbose logging, and social account linking for OmniAuth integrations.

## Prerequisites

1. **FusionAuth Instance:** Running FusionAuth server (default: <http://localhost:9011>)
2. **API Key:** FusionAuth API key with user import permissions
3. **Ruby:** Ruby 2.7 or higher with bundler
4. **Export File:** JSON export file from your Rails-based authentication system. Refer to the [FusionAuth Users documentation](https://fusionauth.io/docs/apis/users#import-users) for details.

## Installation

1. Install dependencies.

```bash
bundle install
```

2. Make the script executable.

```bash
chmod +x import.rb
```

3. (Optional) Make the wrapper script executable.

```bash
chmod +x import.sh
```

## Usage

```bash
./import.rb -k YOUR_API_KEY -u users_export_file.json
```

This imports users from the file into FusionAuth's default tenant and application.

### Advanced Usage

```bash
./import.rb \
--fusionauth-api-key YOUR_API_KEY \
--users-file users_export_file.json \
--fusionauth-url http://localhost:9011 \
--fusionauth-tenant-id YOUR_TENANT_ID \
--source-system devise \
--register-users app-id-1,app-id-2,app-id-3 \
--link-social-accounts \
--verbose
```

## Command Line Options

| Option | Short | Required | Default | Description |
|--------|-------|----------|---------|-------------|
| `--users-file` | `-u` | No | `users.json` | Path to the exported JSON user file |
| `--fusionauth-api-key` | `-k` | **Yes** | - | FusionAuth API key |
| `--fusionauth-url` | `-f` | No | `http://localhost:9011` | FusionAuth instance URL |
| `--fusionauth-tenant-id` | `-t` | No | - | Tenant Id (required if multiple tenants exist) |
| `--source-system` | `-s` | No | Auto-detected | Source system: `devise`, `rails_auth`, or `omniauth` |
| `--register-users` | `-r` | No | - | Comma-separated list of application Ids |
| `--link-social-accounts` | `-l` | No | `false` | Link social accounts for OmniAuth users |
| `--verbose` | `-v` | No | `false` | Enable detailed logging |
| `--help` | `-h` | No | - | Show help message |

## Supported Authentication Systems

**Devise:** Imports users, encrypted passwords, and user metadata. Preserves email confirmation status and account locking.

**OmniAuth:** Imports social accounts with identity provider linking. Specify social provider and provider user Id in the `user[x].data` field.

**Rails In-Built Authentication:** Imports users, confirmation status, and sign-in tracking data.
70 changes: 70 additions & 0 deletions rails/export-scripts/built-in-auth/export_users_for_fusionauth.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#!/usr/bin/env ruby

require_relative '../config/environment'
require 'json'
require 'securerandom'

puts "Starting user export for Rails Authentication users..."
puts "Found #{User.count} users to export"

users_data = User.all.map do |user|
puts "Exporting user: #{user.email}"

# Parse bcrypt hash according to FusionAuth requirements:
# Example: $2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy
# Should be split to:
# factor: 10
# salt: N9qo8uLOickgx2ZMRZoMye (first 22 chars after factor)
# password: IjZAgcfl7p92ldGxad68LJZdL17lhWy (remaining chars)

bcrypt_factor = 10 # default
bcrypt_salt = ""
bcrypt_password = ""

if user.password_digest&.match(/^\$2[aby]\$(\d+)\$(.+)$/)
bcrypt_factor = $1.to_i
salt_and_hash = $2

bcrypt_salt = salt_and_hash[0, 22]
bcrypt_password = salt_and_hash[22..-1]
end

user_data = {
email: user.email,
username: user.email,
fullName: user.name,
password: bcrypt_password,
encryptionScheme: "bcrypt",
factor: bcrypt_factor,
salt: bcrypt_salt,
passwordChangeRequired: false,
verified: user.confirmed?,
active: user.confirmed?,
registrations: [
{
id: SecureRandom.uuid,
applicationId: "e9fdb985-9173-4e01-9d73-ac2d60d1dc8e",
verified: user.confirmed?,
roles: ["user"]
}
],
# Additional user data
data: {
migrated_from: "rails_authentication",
original_id: user.id
}
}

user_data
end

# Save to JSON file
filename = "users_export.json"

File.open(filename, 'w') do |file|
file.write(JSON.pretty_generate(users_data))
end

puts "\nExport complete!"
puts "Saved #{users_data.length} users to #{filename}"
puts "Total users exported: #{users_data.count}"
30 changes: 30 additions & 0 deletions rails/export-scripts/built-in-auth/users_export.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"users": [
{
"email": "sarah.johnson@techcorp.com",
"username": "sarah.johnson@techcorp.com",
"fullName": "Sarah Johnson",
"password": "ANzpvmDwOpcY4GU0fpNDsCrB6l9Ad62",
"encryptionScheme": "bcrypt",
"factor": 12,
"salt": "jTZOY/BQkbKJNMaCuy39Cu",
"passwordChangeRequired": false,
"verified": true,
"active": true,
"registrations": [
{
"id": "72efaea3-267a-49cc-a6f0-aa8f0b096b29",
"applicationId": "e9fdb985-9173-4e01-9d73-ac2d60d1dc8e",
"verified": true,
"roles": [
"user"
]
}
],
"data": {
"migrated_from": "rails_authentication",
"original_id": 1
}
}
]
}
71 changes: 71 additions & 0 deletions rails/export-scripts/devise/export_users_for_fusionauth.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#!/usr/bin/env ruby

require_relative 'config/environment'
require 'json'
require 'securerandom'

puts "Starting user export for Devise users..."
puts "Found #{User.count} users to export"

users_data = User.all.map do |user|
puts "Exporting user: #{user.email}"

# Parse bcrypt hash according to FusionAuth requirements:
# Example: $2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy
# Should be split to:
# factor: 10
# salt: N9qo8uLOickgx2ZMRZoMye (first 22 chars after factor)
# password: IjZAgcfl7p92ldGxad68LJZdL17lhWy (remaining chars)

bcrypt_factor = 10 # default
bcrypt_salt = ""
bcrypt_password = ""

if user.encrypted_password&.match(/^\$2[aby]\$(\d+)\$(.+)$/)
bcrypt_factor = $1.to_i
salt_and_hash = $2

bcrypt_salt = salt_and_hash[0, 22]
bcrypt_password = salt_and_hash[22..-1]
end

user_data = {
email: user.email,
username: user.email,
password: bcrypt_password,
encryptionScheme: "bcrypt",
factor: bcrypt_factor,
salt: bcrypt_salt,
passwordChangeRequired: false,
verified: user.respond_to?(:confirmed?) ? user.confirmed? : true,
active: true,
registrations: [
{
id: SecureRandom.uuid,
applicationId: "e9fdb985-9173-4e01-9d73-ac2d60d1dc8e",
verified: user.respond_to?(:confirmed?) ? user.confirmed? : true,
roles: ["user"]
}
],
data: {
source_system: "devise",
original_user_id: user.id,
locked_at: user.respond_to?(:locked_at) ? user.locked_at : nil,
confirmation_token: user.respond_to?(:confirmation_token) ? user.confirmation_token : nil,
last_sign_in_ip: user.respond_to?(:last_sign_in_ip) ? user.last_sign_in_ip : nil,
current_sign_in_ip: user.respond_to?(:current_sign_in_ip) ? user.current_sign_in_ip : nil
}
}

user_data
end

# Write to file with proper FusionAuth format
export_data = { users: users_data }
filename = "users_export.json"
File.write(filename, JSON.pretty_generate(export_data))

puts ""
puts "Export completed successfully!"
puts "File saved as: #{filename}"
puts "Total users exported: #{users_data.count}"
33 changes: 33 additions & 0 deletions rails/export-scripts/devise/users_export.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"users": [
{
"email": "jennifer.adams@techstart.com",
"username": "jennifer.adams@techstart.com",
"password": "wSMHfHu84ns5n4WeGY0Jn.ZwZsLj3zC",
"encryptionScheme": "bcrypt",
"factor": 12,
"salt": "Oa88b1GmziTesQzGkMSYyu",
"passwordChangeRequired": false,
"verified": true,
"active": true,
"registrations": [
{
"id": "cc09b582-d35b-44b1-8331-f8c329006079",
"applicationId": "e9fdb985-9173-4e01-9d73-ac2d60d1dc8e",
"verified": true,
"roles": [
"user"
]
}
],
"data": {
"source_system": "devise",
"original_user_id": 1,
"locked_at": null,
"confirmation_token": null,
"last_sign_in_ip": null,
"current_sign_in_ip": null
}
}
]
}
54 changes: 54 additions & 0 deletions rails/export-scripts/omniauth/export_users_for_fusionauth.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#!/usr/bin/env ruby

# Simple User Export Script for OmniAuth Users
# Exports users as plain JSON

require_relative 'config/environment'
require 'json'
require 'securerandom'

puts "Starting user export for OmniAuth users..."
puts "Found #{User.count} users to export"

users_data = User.all.map do |user|
puts "Exporting user: #{user.email} (#{user.provider})"

{
email: user.email,
username: user.email,
fullName: user.name,
password: SecureRandom.alphanumeric(12) + "!",
verified: true,
active: user.active,
imageUrl: user.image_url,
registrations: [
{
id: SecureRandom.uuid,
applicationId: "e9fdb985-9173-4e01-9d73-ac2d60d1dc8e",
verified: true,
roles: ["user"]
}
],
data: {
source_system: "omniauth",
original_user_id: user.id,
oauth_provider: user.provider,
oauth_uid: user.uid,
locked_at: nil,
confirmation_token: nil,
last_sign_in_ip: nil,
current_sign_in_ip: nil
}
}
end

# Write to file with proper FusionAuth format
export_data = { users: users_data }
filename = "users_export.json"
File.write(filename, JSON.pretty_generate(export_data))

puts ""
puts "Export completed successfully!"
puts "File saved as: #{filename}"
puts "Total users exported: #{users_data.count}"
puts "Providers: #{users_data.group_by { |u| u[:data][:oauth_provider] }.transform_values(&:count)}"
33 changes: 33 additions & 0 deletions rails/export-scripts/omniauth/users_export.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"users": [
{
"email": "alexandra.kim@techventures.com",
"username": "alexandra.kim@techventures.com",
"fullName": "Alexandra Kim",
"password": "oceghPW47j1f!",
"verified": true,
"active": true,
"imageUrl": "https://via.placeholder.com/80/667eea/ffffff?text=AK",
"registrations": [
{
"id": "d068cd77-4c94-470f-bc83-399b1b63023a",
"applicationId": "e9fdb985-9173-4e01-9d73-ac2d60d1dc8e",
"verified": true,
"roles": [
"user"
]
}
],
"data": {
"source_system": "omniauth",
"original_user_id": 1,
"oauth_provider": "google_oauth2",
"oauth_uid": "108234567890123456789",
"locked_at": null,
"confirmation_token": null,
"last_sign_in_ip": null,
"current_sign_in_ip": null
}
}
]
}
Loading